Browse files

Longview (Consolidate item collection setup)

My previous change broke use of the MetadataWorkspace in some multi-threading scenarios with a cached workspace. This was due to not fully understanding the haphazard nature by which item collections are set on the workspace. This change takes advantage of Lazy to handle deferred initialization of item collections in a consistent and thread-safe manner. This is coupled with new constructors for MetadataWorkspace that take delegates to set up the lazy initialization. The previous method of registering item collections (RegisterItemCollection) is now obsoleted in favor of these new constructors.
  • Loading branch information...
1 parent e5ae583 commit a5faddeca2bee08636f1b7b3af8389bd4119f4cd @ajcvickers ajcvickers committed Feb 13, 2013
Showing with 915 additions and 611 deletions.
  1. +1 −18 src/EntityFramework/Core/Common/CommandTrees/DbCommandTree.cs
  2. +55 −103 src/EntityFramework/Core/EntityClient/EntityConnection.cs
  3. +23 −13 src/EntityFramework/Core/Mapping/DefaultObjectMappingItemCollection.cs
  4. +21 −21 src/EntityFramework/Core/Mapping/StorageMappingItemCollection.cs
  5. +4 −3 src/EntityFramework/Core/Mapping/ViewGeneration/Utils/ExternalCalls.cs
  6. +142 −155 src/EntityFramework/Core/Metadata/Edm/MetadataWorkspace.cs
  7. +0 −3 src/EntityFramework/Core/Objects/ELinq/CompiledELinqQueryState.cs
  8. +0 −3 src/EntityFramework/Core/Objects/ELinq/ELinqQueryState.cs
  9. +0 −3 src/EntityFramework/Core/Objects/Internal/EntitySqlQueryState.cs
  10. +1 −56 src/EntityFramework/Core/Objects/ObjectContext.cs
  11. +0 −1 src/EntityFramework/Core/Objects/ObjectQuery.cs
  12. +0 −1 src/EntityFramework/Core/Objects/ObjectViewFactory.cs
  13. +8 −16 src/EntityFramework/ModelConfiguration/Edm/DbDatabaseMappingExtensions.cs
  14. +0 −9 src/EntityFramework/Properties/Resources.cs
  15. +0 −3 src/EntityFramework/Properties/Resources.resx
  16. +72 −67 test/EntityFramework/FunctionalTests.Transitional/MetadataMapping/EnumOCMappingTests.cs
  17. +41 −0 test/EntityFramework/FunctionalTests.Transitional/TestHelpers/TestBase.cs
  18. +26 −10 test/EntityFramework/FunctionalTests/ProductivityApi/ConnectionTests.cs
  19. +28 −0 test/EntityFramework/FunctionalTests/ProductivityApi/MultiThreadingTests.cs
  20. +51 −0 test/EntityFramework/UnitTests/Core/Common/CommandTrees/DbCommandTreeTests.cs
  21. +67 −66 test/EntityFramework/UnitTests/Core/EntityClient/EntityConnectionTests.cs
  22. +27 −0 test/EntityFramework/UnitTests/Core/Mapping/StorageMappingItemCollectionTests.cs
  23. +27 −0 test/EntityFramework/UnitTests/Core/Mapping/ViewGeneration/Utils/ExternalCallsTests.cs
  24. +298 −0 test/EntityFramework/UnitTests/Core/Metadata/Edm/MetadataWorkspaceTests.cs
  25. +6 −6 test/EntityFramework/UnitTests/Core/Objects/Internal/ObjectQueryExecutionPlanFactoryTests.cs
  26. +14 −54 test/EntityFramework/UnitTests/Core/Objects/ObjectContextTests.cs
  27. +3 −0 test/EntityFramework/UnitTests/UnitTests.csproj
View
19 src/EntityFramework/Core/Common/CommandTrees/DbCommandTree.cs
@@ -40,24 +40,7 @@ internal DbCommandTree(MetadataWorkspace metadata, DataSpace dataSpace)
throw new ArgumentException(Strings.Cqt_CommandTree_InvalidDataSpace, "dataSpace");
}
- //
- // Create the tree's metadata workspace and initalize commonly used types.
- //
- var effectiveMetadata = new MetadataWorkspace();
-
- //While EdmItemCollection and StorageitemCollections are required
- //ObjectItemCollection may or may not be registered on the workspace yet.
- //So register the ObjectItemCollection if it exists.
- ItemCollection objectItemCollection;
- if (metadata.TryGetItemCollection(DataSpace.OSpace, out objectItemCollection))
- {
- effectiveMetadata.RegisterItemCollection(objectItemCollection);
- }
- effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.CSpace));
- effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.CSSpace));
- effectiveMetadata.RegisterItemCollection(metadata.GetItemCollection(DataSpace.SSpace));
-
- _metadata = effectiveMetadata;
+ _metadata = metadata;
_dataSpace = dataSpace;
}
View
158 src/EntityFramework/Core/EntityClient/EntityConnection.cs
@@ -8,6 +8,7 @@ namespace System.Data.Entity.Core.EntityClient
using System.Data.Entity.Config;
using System.Data.Entity.Core.Common;
using System.Data.Entity.Core.EntityClient.Internal;
+ using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Resources;
using System.Data.Entity.Utilities;
@@ -97,10 +98,8 @@ public EntityConnection(string connectionString)
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope",
Justification = "Object is in fact passed to property of the class and gets Disposed properly in the Dispose() method.")]
public EntityConnection(MetadataWorkspace workspace, DbConnection connection)
- : this(workspace, connection, false, false)
+ : this(Check.NotNull(workspace, "workspace"), Check.NotNull(connection, "connection"), false, false)
{
- Check.NotNull(workspace, "workspace");
- Check.NotNull(connection, "connection");
}
/// <summary>
@@ -112,10 +111,9 @@ public EntityConnection(MetadataWorkspace workspace, DbConnection connection)
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope",
Justification = "Object is in fact passed to property of the class and gets Disposed properly in the Dispose() method.")]
public EntityConnection(MetadataWorkspace workspace, DbConnection connection, bool entityConnectionOwnsStoreConnection)
- : this(workspace, connection, false, entityConnectionOwnsStoreConnection)
+ : this(Check.NotNull(workspace, "workspace"), Check.NotNull(connection, "connection"),
+ false, entityConnectionOwnsStoreConnection)
{
- Check.NotNull(workspace, "workspace");
- Check.NotNull(connection, "connection");
}
/// <summary>
@@ -419,87 +417,62 @@ public virtual DbConnection StoreConnection
/// <summary>
/// Gets the metadata workspace used by this connection
/// </summary>
- [CLSCompliant(false)]
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate"), CLSCompliant(false)]
public virtual MetadataWorkspace GetMetadataWorkspace()
{
- return GetMetadataWorkspace(initializeAllCollections: true);
- }
-
- private static bool ShouldRecalculateMetadataArtifactLoader(List<MetadataArtifactLoader> loaders)
- {
- if (loaders.Any(loader => loader.GetType() == typeof(MetadataArtifactLoaderCompositeFile)))
+ if (_metadataWorkspace != null)
{
- // the loaders had folders in it
- return true;
+ return _metadataWorkspace;
}
- // in the case that loaders only contains resources or file name, we trust the cache
- return false;
- }
+ var loaders = new List<MetadataArtifactLoader>();
+ var paths = _effectiveConnectionOptions[EntityConnectionStringBuilder.MetadataParameterName];
- [ResourceExposure(ResourceScope.None)] // The resource( path name) is not exposed to the callers of this method
- [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
- //For SplitPaths call and we pick the file names from class variable.
- internal virtual MetadataWorkspace GetMetadataWorkspace(bool initializeAllCollections)
- {
- Debug.Assert(
- _metadataWorkspace != null || _effectiveConnectionOptions != null,
- "The effective connection options is null, which should never be");
- if (_metadataWorkspace == null
- ||
- (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)))
+ if (!string.IsNullOrEmpty(paths))
{
- // This lock is to ensure that the connection string and the metadata workspace are in a consistent state, that is, you
- // don't get a metadata workspace not matching what's described by the connection string
- lock (_connectionStringLock)
+ loaders = MetadataCache.GetOrCreateMetdataArtifactLoader(paths);
+
+ if (ShouldRecalculateMetadataArtifactLoader(loaders))
{
- EdmItemCollection edmItemCollection = null;
- if (_metadataWorkspace == null)
- {
- var workspace = new MetadataWorkspace();
- var loaders = new List<MetadataArtifactLoader>();
- var paths = _effectiveConnectionOptions[EntityConnectionStringBuilder.MetadataParameterName];
+ // the loaders contains folders that might get updated during runtime, so we have to recalculate the loaders again
+ _artifactLoader = MetadataArtifactLoader.Create(MetadataCache.SplitPaths(paths));
+ }
+ else
+ {
+ _artifactLoader = MetadataArtifactLoader.Create(loaders);
+ }
+ }
+ else
+ {
+ _artifactLoader = MetadataArtifactLoader.Create(loaders);
+ }
- if (!string.IsNullOrEmpty(paths))
- {
- loaders = MetadataCache.GetOrCreateMetdataArtifactLoader(paths);
+ // Build a string as the key and look up the MetadataCache for a match
+ var edmCacheKey = CreateMetadataCacheKey(_artifactLoader.GetOriginalPaths(DataSpace.CSpace), null, null);
- if (!ShouldRecalculateMetadataArtifactLoader(loaders))
- {
- _artifactLoader = MetadataArtifactLoader.Create(loaders);
- }
- else
- {
- // the loaders contains folders that might get updated during runtime, so we have to recalculate the loaders again
- _artifactLoader = MetadataArtifactLoader.Create(MetadataCache.SplitPaths(paths));
- }
- }
- else
- {
- _artifactLoader = MetadataArtifactLoader.Create(loaders);
- }
+ // Check the MetadataCache for an entry with this key
+ object entryToken;
+ var edmItemCollection = MetadataCache.GetOrCreateEdmItemCollection(edmCacheKey, _artifactLoader, out entryToken);
- edmItemCollection = LoadEdmItemCollection(workspace, _artifactLoader);
- _metadataWorkspace = workspace;
- }
- else
- {
- edmItemCollection = (EdmItemCollection)_metadataWorkspace.GetItemCollection(DataSpace.CSpace);
- }
+ var mappingLoader = new Lazy<StorageMappingItemCollection>(
+ () => StorageMappingLoader(_storeConnection, _effectiveConnectionOptions, edmItemCollection));
- if (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
- {
- LoadStoreItemCollections(
- _metadataWorkspace, _storeConnection, _effectiveConnectionOptions, edmItemCollection, _artifactLoader);
- _artifactLoader = null;
- _initialized = true;
- }
- }
- }
+ _metadataWorkspace = new MetadataWorkspace(
+ () => edmItemCollection,
+ () => mappingLoader.Value.StoreItemCollection,
+ () => mappingLoader.Value);
+
+ // TODO: Fix this as part of metadata caching simplification to cache workspaces themselves
+ _metadataWorkspace.AddMetadataEntryToken(entryToken);
return _metadataWorkspace;
}
+ private static bool ShouldRecalculateMetadataArtifactLoader(IEnumerable<MetadataArtifactLoader> loaders)
+ {
+ return loaders.Any(loader => loader.GetType() == typeof(MetadataArtifactLoaderCompositeFile));
+ }
+
/// <summary>
/// Gets the current transaction that this connection is enlisted in
/// </summary>
@@ -1018,6 +991,7 @@ private void ChangeConnectionString(string newConnectionString)
// Now we have sufficient information and verified the configuration string is good, use them for this connection object
// Failure should not occur from this point to the end of this method
_providerFactory = factory;
+
_metadataWorkspace = null;
ClearTransactions();
@@ -1048,35 +1022,11 @@ private void ChangeConnectionString(string newConnectionString)
return keywordValue;
}
- private static EdmItemCollection LoadEdmItemCollection(MetadataWorkspace workspace, MetadataArtifactLoader artifactLoader)
- {
- // Build a string as the key and look up the MetadataCache for a match
- var edmCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(DataSpace.CSpace), null, null);
-
- // Check the MetadataCache for an entry with this key
- object entryToken;
- var edmItemCollection = MetadataCache.GetOrCreateEdmItemCollection(
- edmCacheKey,
- artifactLoader,
- out entryToken);
- workspace.RegisterItemCollection(edmItemCollection);
-
- // Adding the edm metadata entry token to the workspace, to make sure that this token remains alive till workspace is alive
- workspace.AddMetadataEntryToken(entryToken);
-
- return edmItemCollection;
- }
-
- private static void LoadStoreItemCollections(
- MetadataWorkspace workspace,
+ private StorageMappingItemCollection StorageMappingLoader(
DbConnection storeConnection,
DbConnectionOptions connectionOptions,
- EdmItemCollection edmItemCollection,
- MetadataArtifactLoader artifactLoader)
+ EdmItemCollection edmItemCollection)
{
- Debug.Assert(
- workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace), "C-Space must be loaded before loading S or C-S space");
-
// The provider connection string is optional; if it has not been specified,
// we pick up the store's connection string.
//
@@ -1089,7 +1039,7 @@ private static EdmItemCollection LoadEdmItemCollection(MetadataWorkspace workspa
// Build a string as the key and look up the MetadataCache for a match
var storeCacheKey = CreateMetadataCacheKey(
- artifactLoader.GetOriginalPaths(),
+ _artifactLoader.GetOriginalPaths(),
connectionOptions[EntityConnectionStringBuilder.ProviderParameterName],
providerConnectionString);
@@ -1098,15 +1048,17 @@ private static EdmItemCollection LoadEdmItemCollection(MetadataWorkspace workspa
var mappingCollection =
MetadataCache.GetOrCreateStoreAndMappingItemCollections(
storeCacheKey,
- artifactLoader,
+ _artifactLoader,
edmItemCollection,
out entryToken);
- workspace.RegisterItemCollection(mappingCollection.StoreItemCollection);
- workspace.RegisterItemCollection(mappingCollection);
+ _artifactLoader = null;
+ _initialized = true;
+
+ // TODO: Fix this as part of metadata caching simplification to cache workspaces themselves
+ _metadataWorkspace.AddMetadataEntryToken(entryToken);
- // Adding the store metadata entry token to the workspace
- workspace.AddMetadataEntryToken(entryToken);
+ return mappingCollection;
}
/// <summary>
View
36 src/EntityFramework/Core/Mapping/DefaultObjectMappingItemCollection.cs
@@ -32,21 +32,21 @@ internal class DefaultObjectMappingItemCollection : MappingItemCollection
DebugCheck.NotNull(edmCollection);
DebugCheck.NotNull(objectCollection);
- m_edmCollection = edmCollection;
- m_objectCollection = objectCollection;
+ _edmCollection = edmCollection;
+ _objectCollection = objectCollection;
- var cspaceTypes = m_edmCollection.GetPrimitiveTypes();
+ var cspaceTypes = _edmCollection.GetPrimitiveTypes();
foreach (var type in cspaceTypes)
{
- var ospaceType = m_objectCollection.GetMappedPrimitiveType(type.PrimitiveTypeKind);
+ var ospaceType = _objectCollection.GetMappedPrimitiveType(type.PrimitiveTypeKind);
Debug.Assert(ospaceType != null, "all primitive type must have been loaded");
AddInternalMapping(new ObjectTypeMapping(ospaceType, type), _clrTypeIndexes, _edmTypeIndexes);
}
}
- private readonly ObjectItemCollection m_objectCollection;
- private readonly EdmItemCollection m_edmCollection;
+ private readonly ObjectItemCollection _objectCollection;
+ private readonly EdmItemCollection _edmCollection;
//Indexes into the type mappings collection based on clr type name
private Dictionary<string, int> _clrTypeIndexes = new Dictionary<string, int>(StringComparer.Ordinal);
@@ -56,6 +56,16 @@ internal class DefaultObjectMappingItemCollection : MappingItemCollection
private readonly object _lock = new object();
+ public ObjectItemCollection ObjectItemCollection
+ {
+ get { return _objectCollection; }
+ }
+
+ public EdmItemCollection EdmItemCollection
+ {
+ get { return _edmCollection; }
+ }
+
/// <summary>
/// Search for a Mapping metadata with the specified type key.
/// </summary>
@@ -90,7 +100,7 @@ internal override bool TryGetMap(string identity, DataSpace typeSpace, bool igno
if (ignoreCase)
{
// Get the correct casing of the identity first if we are asked to do ignore case
- if (!m_edmCollection.TryGetItem(identity, true, out cdmType))
+ if (!_edmCollection.TryGetItem(identity, true, out cdmType))
{
map = null;
return false;
@@ -108,18 +118,18 @@ internal override bool TryGetMap(string identity, DataSpace typeSpace, bool igno
if (cdmType != null
||
- m_edmCollection.TryGetItem(identity, ignoreCase, out cdmType))
+ _edmCollection.TryGetItem(identity, ignoreCase, out cdmType))
{
// If the mapping is not already loaded, then get the mapping ospace type
- m_objectCollection.TryGetOSpaceType(cdmType, out clrType);
+ _objectCollection.TryGetOSpaceType(cdmType, out clrType);
}
}
else if (typeSpace == DataSpace.OSpace)
{
if (ignoreCase)
{
// Get the correct casing of the identity first if we are asked to do ignore case
- if (!m_objectCollection.TryGetItem(identity, true, out clrType))
+ if (!_objectCollection.TryGetItem(identity, true, out clrType))
{
map = null;
return false;
@@ -137,11 +147,11 @@ internal override bool TryGetMap(string identity, DataSpace typeSpace, bool igno
if (clrType != null
||
- m_objectCollection.TryGetItem(identity, ignoreCase, out clrType))
+ _objectCollection.TryGetItem(identity, ignoreCase, out clrType))
{
// If the mapping is not already loaded, get the mapping cspace type
var cspaceTypeName = ObjectItemCollection.TryGetMappingCSpaceTypeIdentity(clrType);
- m_edmCollection.TryGetItem(cspaceTypeName, out cdmType);
+ _edmCollection.TryGetItem(cspaceTypeName, out cdmType);
}
}
@@ -342,7 +352,7 @@ private EdmType ConvertCSpaceToOSpaceType(EdmType cdmType)
}
else if (Helper.IsPrimitiveType(cdmType))
{
- clrType = m_objectCollection.GetMappedPrimitiveType(((PrimitiveType)cdmType).PrimitiveTypeKind);
+ clrType = _objectCollection.GetMappedPrimitiveType(((PrimitiveType)cdmType).PrimitiveTypeKind);
}
else
{
View
42 src/EntityFramework/Core/Mapping/StorageMappingItemCollection.cs
@@ -594,14 +594,14 @@ private static bool VerifyViewsHaveNotChanged(MetadataWorkspace workspace, Entit
}
//EdmItemCollection that is associated with the MSL Loader.
- private EdmItemCollection m_edmCollection;
+ private EdmItemCollection _edmCollection;
//StoreItemCollection that is associated with the MSL Loader.
- private StoreItemCollection m_storeItemCollection;
+ private StoreItemCollection _storeItemCollection;
private ViewDictionary m_viewDictionary;
private double m_mappingVersion = XmlConstants.UndefinedVersion;
- private MetadataWorkspace m_workspace;
+ private MetadataWorkspace _workspace;
// In this version, we won't allow same types in CSpace to map to different types in store. If the same type
// need to be reused, the store type must be the same. To keep track of this, we need to keep track of the member
@@ -647,8 +647,8 @@ internal enum InterestingMembersKind
Check.NotNull(storeCollection, "storeCollection");
Check.NotNull(filePaths, "filePaths");
- m_edmCollection = edmCollection;
- m_storeItemCollection = storeCollection;
+ _edmCollection = edmCollection;
+ _storeItemCollection = storeCollection;
// Wrap the file paths in instances of the MetadataArtifactLoader class, which provides
// an abstraction and a uniform interface over a diverse set of metadata artifacts.
@@ -762,8 +762,8 @@ internal enum InterestingMembersKind
DebugCheck.NotNull(edmCollection);
DebugCheck.NotNull(storeCollection);
- m_edmCollection = edmCollection;
- m_storeItemCollection = storeCollection;
+ _edmCollection = edmCollection;
+ _storeItemCollection = storeCollection;
Dictionary<EntitySetBase, GeneratedView> userDefinedQueryViewsDict;
Dictionary<OfTypeQVCacheKey, GeneratedView> userDefinedQueryViewsOfTypeDict;
@@ -772,9 +772,9 @@ internal enum InterestingMembersKind
var errors = new List<EdmSchemaError>();
- if (m_edmCollection.EdmVersion != XmlConstants.UndefinedVersion
- && m_storeItemCollection.StoreSchemaVersion != XmlConstants.UndefinedVersion
- && m_edmCollection.EdmVersion != m_storeItemCollection.StoreSchemaVersion)
+ if (_edmCollection.EdmVersion != XmlConstants.UndefinedVersion
+ && _storeItemCollection.StoreSchemaVersion != XmlConstants.UndefinedVersion
+ && _edmCollection.EdmVersion != _storeItemCollection.StoreSchemaVersion)
{
errors.Add(
new EdmSchemaError(
@@ -783,9 +783,9 @@ internal enum InterestingMembersKind
}
else
{
- var expectedVersion = m_edmCollection.EdmVersion != XmlConstants.UndefinedVersion
- ? m_edmCollection.EdmVersion
- : m_storeItemCollection.StoreSchemaVersion;
+ var expectedVersion = _edmCollection.EdmVersion != XmlConstants.UndefinedVersion
+ ? _edmCollection.EdmVersion
+ : _storeItemCollection.StoreSchemaVersion;
errors.AddRange(
LoadItems(xmlReaders, filePaths, userDefinedQueryViewsDict, userDefinedQueryViewsOfTypeDict, expectedVersion));
}
@@ -812,14 +812,14 @@ internal MetadataWorkspace Workspace
{
get
{
- if (m_workspace == null)
+ if (_workspace == null)
{
- m_workspace = new MetadataWorkspace();
- m_workspace.RegisterItemCollection(m_edmCollection);
- m_workspace.RegisterItemCollection(m_storeItemCollection);
- m_workspace.RegisterItemCollection(this);
+ _workspace = new MetadataWorkspace(
+ () => _edmCollection,
+ () => _storeItemCollection,
+ () => this);
}
- return m_workspace;
+ return _workspace;
}
}
@@ -828,7 +828,7 @@ internal MetadataWorkspace Workspace
/// </summary>
internal EdmItemCollection EdmItemCollection
{
- get { return m_edmCollection; }
+ get { return _edmCollection; }
}
/// <summary>
@@ -844,7 +844,7 @@ public double MappingVersion
/// </summary>
internal StoreItemCollection StoreItemCollection
{
- get { return m_storeItemCollection; }
+ get { return _storeItemCollection; }
}
/// <summary>
View
7 src/EntityFramework/Core/Mapping/ViewGeneration/Utils/ExternalCalls.cs
@@ -79,9 +79,10 @@ internal static bool IsReservedKeyword(string name)
DebugCheck.NotNull(functionParameters);
DebugCheck.NotNull(edmItemCollection);
- var workspace = new MetadataWorkspace();
- workspace.RegisterItemCollection(edmItemCollection);
- Perspective perspective = new ModelPerspective(workspace);
+ var perspective = new ModelPerspective(new MetadataWorkspace(
+ () => edmItemCollection,
+ () => null,
+ () => null));
// Since we compile lambda expression and generate variables from the function parameter definitions,
// the returned DbLambda will contain variable types that match function parameter types.
View
297 src/EntityFramework/Core/Metadata/Edm/MetadataWorkspace.cs
@@ -27,25 +27,88 @@ namespace System.Data.Entity.Core.Metadata.Edm
/// <summary>
/// Runtime Metadata Workspace
/// </summary>
+ [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
public class MetadataWorkspace
{
- private EdmItemCollection _itemsCSpace;
- private StoreItemCollection _itemsSSpace;
- private ObjectItemCollection _itemsOSpace;
- private StorageMappingItemCollection _itemsCSSpace;
- private DefaultObjectMappingItemCollection _itemsOCSpace;
+ private Lazy<EdmItemCollection> _itemsCSpace;
+ private Lazy<StoreItemCollection> _itemsSSpace;
+ private Lazy<ObjectItemCollection> _itemsOSpace;
+ private Lazy<StorageMappingItemCollection> _itemsCSSpace;
+ private Lazy<DefaultObjectMappingItemCollection> _itemsOCSpace;
private List<object> _cacheTokens;
private bool _foundAssemblyWithAttribute;
private double _schemaVersion = XmlConstants.UndefinedVersion;
private Guid _metadataWorkspaceId = Guid.Empty;
- private readonly object _lock = new object();
/// <summary>
/// Constructs the new instance of runtime metadata workspace
/// </summary>
public MetadataWorkspace()
{
+ _itemsOSpace = new Lazy<ObjectItemCollection>(() => new ObjectItemCollection(), isThreadSafe: true);
+ }
+
+ /// <summary>
+ /// Constructs a <see cref="MetadataWorkspace"/> with loaders for all item collections (<see cref="ItemCollection"/>)
+ /// needed by EF except the o/c mapping which will be created automatically based on the given o-space and c-space
+ /// loaders. The item collection delegates are executed lazily when a given collection is used for the first
+ /// time. It is acceptable to pass a delegate that returns null if the collection will never be used, but this
+ /// is rarely done, and any attempt by EF to use the collection in such cases will result in an exception.
+ /// </summary>
+ /// <param name="cSpaceLoader">Delegate to return the c-space (CSDL) item collection.</param>
+ /// <param name="sSpaceLoader">Delegate to return the s-space (SSDL) item collection.</param>
+ /// <param name="csMappingLoader">Delegate to return the c/s mapping (MSL) item collection.</param>
+ /// <param name="oSpaceLoader">Delegate to return the o-space item collection.</param>
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "c")]
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "o")]
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
+ public MetadataWorkspace(
+ Func<EdmItemCollection> cSpaceLoader,
+ Func<StoreItemCollection> sSpaceLoader,
+ Func<StorageMappingItemCollection> csMappingLoader,
+ Func<ObjectItemCollection> oSpaceLoader)
+ {
+ Check.NotNull(cSpaceLoader, "cSpaceLoader");
+ Check.NotNull(sSpaceLoader, "sSpaceLoader");
+ Check.NotNull(csMappingLoader, "csMappingLoader");
+ Check.NotNull(oSpaceLoader, "oSpaceLoader");
+
+ _itemsCSpace = new Lazy<EdmItemCollection>(cSpaceLoader, isThreadSafe: true);
+ _itemsSSpace = new Lazy<StoreItemCollection>(sSpaceLoader, isThreadSafe: true);
+ _itemsOSpace = new Lazy<ObjectItemCollection>(oSpaceLoader, isThreadSafe: true);
+ _itemsCSSpace = new Lazy<StorageMappingItemCollection>(csMappingLoader, isThreadSafe: true);
+ _itemsOCSpace = new Lazy<DefaultObjectMappingItemCollection>(
+ () => new DefaultObjectMappingItemCollection(_itemsCSpace.Value, _itemsOSpace.Value), isThreadSafe: true);
+ }
+
+ /// <summary>
+ /// Constructs a <see cref="MetadataWorkspace"/> with loaders for all item collections (<see cref="ItemCollection"/>)
+ /// that come from traditional EDMX mapping. Default o-space and o/c mapping collections will be used.
+ /// The item collection delegates are executed lazily when a given collection is used for the first
+ /// time. It is acceptable to pass a delegate that returns null if the collection will never be used, but this
+ /// is rarely done, and any attempt by EF to use the collection in such cases will result in an exception.
+ /// </summary>
+ /// <param name="cSpaceLoader">Delegate to return the c-space (CSDL) item collection.</param>
+ /// <param name="sSpaceLoader">Delegate to return the s-space (SSDL) item collection.</param>
+ /// <param name="csMappingLoader">Delegate to return the c/s mapping (MSL) item collection.</param>
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "c")]
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
+ public MetadataWorkspace(
+ Func<EdmItemCollection> cSpaceLoader,
+ Func<StoreItemCollection> sSpaceLoader,
+ Func<StorageMappingItemCollection> csMappingLoader)
+ {
+ Check.NotNull(cSpaceLoader, "cSpaceLoader");
+ Check.NotNull(sSpaceLoader, "sSpaceLoader");
+ Check.NotNull(csMappingLoader, "csMappingLoader");
+
+ _itemsCSpace = new Lazy<EdmItemCollection>(cSpaceLoader, isThreadSafe: true);
+ _itemsSSpace = new Lazy<StoreItemCollection>(sSpaceLoader, isThreadSafe: true);
+ _itemsOSpace = new Lazy<ObjectItemCollection>(() => new ObjectItemCollection(), isThreadSafe: true);
+ _itemsCSSpace = new Lazy<StorageMappingItemCollection>(csMappingLoader, isThreadSafe: true);
+ _itemsOCSpace = new Lazy<DefaultObjectMappingItemCollection>(
+ () => new DefaultObjectMappingItemCollection(_itemsCSpace.Value, _itemsOSpace.Value), isThreadSafe: true);
}
/// <summary>
@@ -70,19 +133,19 @@ public MetadataWorkspace(IEnumerable<string> paths, IEnumerable<Assembly> assemb
EntityUtil.CheckArgumentContainsNull(ref assembliesToConsider, "assembliesToConsider");
Func<AssemblyName, Assembly> resolveReference = (AssemblyName referenceName) =>
- {
- foreach (var assembly in assembliesToConsider)
- {
- if (AssemblyName.ReferenceMatchesDefinition(
- referenceName, new AssemblyName(assembly.FullName)))
- {
- return assembly;
- }
- }
- throw new ArgumentException(
- Strings.AssemblyMissingFromAssembliesToConsider(
- referenceName.FullName), "assembliesToConsider");
- };
+ {
+ foreach (var assembly in assembliesToConsider)
+ {
+ if (AssemblyName.ReferenceMatchesDefinition(
+ referenceName, new AssemblyName(assembly.FullName)))
+ {
+ return assembly;
+ }
+ }
+ throw new ArgumentException(
+ Strings.AssemblyMissingFromAssembliesToConsider(
+ referenceName.FullName), "assembliesToConsider");
+ };
CreateMetadataWorkspaceWithResolver(paths, () => assembliesToConsider, resolveReference);
}
@@ -96,34 +159,37 @@ public MetadataWorkspace(IEnumerable<string> paths, IEnumerable<Assembly> assemb
var composite = MetadataArtifactLoader.CreateCompositeFromFilePaths(
paths.ToArray(), "", new CustomAssemblyResolver(wildcardAssemblies, resolveReference));
- // only create the ItemCollection that has corresponding artifacts
- var dataSpace = DataSpace.CSpace;
- using (var cSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(dataSpace)))
+ _itemsOSpace = new Lazy<ObjectItemCollection>(() => new ObjectItemCollection(), isThreadSafe: true);
+
+ using (var cSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(DataSpace.CSpace)))
{
if (cSpaceReaders.Any())
{
- _itemsCSpace = new EdmItemCollection(cSpaceReaders, composite.GetPaths(dataSpace));
+ var itemCollection = new EdmItemCollection(cSpaceReaders, composite.GetPaths(DataSpace.CSpace));
+ _itemsCSpace = new Lazy<EdmItemCollection>(() => itemCollection, isThreadSafe: true);
+ _itemsOCSpace = new Lazy<DefaultObjectMappingItemCollection>(
+ () => new DefaultObjectMappingItemCollection(itemCollection, _itemsOSpace.Value), isThreadSafe: true);
}
}
- dataSpace = DataSpace.SSpace;
- using (var sSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(dataSpace)))
+ using (var sSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(DataSpace.SSpace)))
{
if (sSpaceReaders.Any())
{
- _itemsSSpace = new StoreItemCollection(sSpaceReaders, composite.GetPaths(dataSpace));
+ var itemCollection = new StoreItemCollection(sSpaceReaders, composite.GetPaths(DataSpace.SSpace));
+ _itemsSSpace = new Lazy<StoreItemCollection>(() => itemCollection, isThreadSafe: true);
}
}
- dataSpace = DataSpace.CSSpace;
- using (var csSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(dataSpace)))
+ using (var csSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(DataSpace.CSSpace)))
{
if (csSpaceReaders.Any()
- && null != _itemsCSpace
- && null != _itemsSSpace)
+ && _itemsCSpace != null
+ && _itemsSSpace != null)
{
- _itemsCSSpace = new StorageMappingItemCollection(
- _itemsCSpace, _itemsSSpace, csSpaceReaders, composite.GetPaths(dataSpace));
+ var mapping = new StorageMappingItemCollection(
+ _itemsCSpace.Value, _itemsSSpace.Value, csSpaceReaders, composite.GetPaths(DataSpace.CSSpace));
+ _itemsCSSpace = new Lazy<StorageMappingItemCollection>(() => mapping, isThreadSafe: true);
}
}
}
@@ -220,121 +286,72 @@ public virtual ItemCollection GetItemCollection(DataSpace dataSpace)
/// <summary>
/// Register the item collection for the space associated with it.
- /// This should be done only once for a space.
- /// If a space already has a registered ItemCollection InvalidOperation exception is thrown
/// </summary>
- /// <param name="collection"> The out parameter collection that needs to be filled up </param>
- /// <returns> </returns>
+ /// <param name="collection">The collection to register.</param>
/// <exception cref="System.ArgumentNullException">if collection argument is null</exception>
- /// <exception cref="System.InvalidOperationException">If there is an ItemCollection that has already been registered for collection's space passed in</exception>
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
[CLSCompliant(false)]
+ [Obsolete("Construct MetadataWorkspace using constructor that accepts metadata loading delegates.")]
public virtual void RegisterItemCollection(ItemCollection collection)
{
Check.NotNull(collection, "collection");
- ItemCollection existing;
-
try
{
switch (collection.DataSpace)
{
case DataSpace.CSpace:
- if (null == (existing = _itemsCSpace))
+ var edmCollection = (EdmItemCollection)collection;
+ if (!SupportedEdmVersions.Contains(edmCollection.EdmVersion))
{
- var edmCollection = (EdmItemCollection)collection;
- if (!SupportedEdmVersions.Contains(edmCollection.EdmVersion))
- {
- throw new InvalidOperationException(
- Strings.EdmVersionNotSupportedByRuntime(
- edmCollection.EdmVersion,
- Helper.GetCommaDelimitedString(
- SupportedEdmVersions
- .Where(e => e != XmlConstants.UndefinedVersion)
- .Select(e => e.ToString(CultureInfo.InvariantCulture)))));
- }
-
- CheckAndSetItemCollectionVersionInWorkSpace(collection);
-
- _itemsCSpace = edmCollection;
+ throw new InvalidOperationException(
+ Strings.EdmVersionNotSupportedByRuntime(
+ edmCollection.EdmVersion,
+ Helper.GetCommaDelimitedString(
+ SupportedEdmVersions
+ .Where(e => e != XmlConstants.UndefinedVersion)
+ .Select(e => e.ToString(CultureInfo.InvariantCulture)))));
}
- break;
- case DataSpace.SSpace:
- if (null == (existing = _itemsSSpace))
+
+ CheckAndSetItemCollectionVersionInWorkSpace(collection);
+ _itemsCSpace = new Lazy<EdmItemCollection>(() => edmCollection, isThreadSafe: true);
+ if (_itemsOCSpace == null)
{
- CheckAndSetItemCollectionVersionInWorkSpace(collection);
- _itemsSSpace = (StoreItemCollection)collection;
+ Debug.Assert(_itemsOSpace != null);
+ _itemsOCSpace =
+ new Lazy<DefaultObjectMappingItemCollection>(
+ () => new DefaultObjectMappingItemCollection(edmCollection, _itemsOSpace.Value));
}
break;
+ case DataSpace.SSpace:
+ CheckAndSetItemCollectionVersionInWorkSpace(collection);
+ _itemsSSpace = new Lazy<StoreItemCollection>(() => (StoreItemCollection)collection, isThreadSafe: true);
+ break;
case DataSpace.OSpace:
- if (null == (existing = _itemsOSpace))
+ _itemsOSpace = new Lazy<ObjectItemCollection>(() => (ObjectItemCollection)collection, isThreadSafe: true);
+ if (_itemsOCSpace == null && _itemsCSpace != null)
{
- _itemsOSpace = (ObjectItemCollection)collection;
+ _itemsOCSpace =
+ new Lazy<DefaultObjectMappingItemCollection>(
+ () => new DefaultObjectMappingItemCollection(_itemsCSpace.Value, _itemsOSpace.Value));
}
break;
case DataSpace.CSSpace:
- if (null == (existing = _itemsCSSpace))
- {
- CheckAndSetItemCollectionVersionInWorkSpace(collection);
- _itemsCSSpace = (StorageMappingItemCollection)collection;
- }
+ CheckAndSetItemCollectionVersionInWorkSpace(collection);
+ _itemsCSSpace = new Lazy<StorageMappingItemCollection>(
+ () => (StorageMappingItemCollection)collection, isThreadSafe: true);
break;
default:
Debug.Assert(collection.DataSpace == DataSpace.OCSpace, "Invalid DataSpace Enum value: " + collection.DataSpace);
-
- if (null == (existing = _itemsOCSpace))
- {
- _itemsOCSpace = (DefaultObjectMappingItemCollection)collection;
- }
+ _itemsOCSpace = new Lazy<DefaultObjectMappingItemCollection>(
+ () => (DefaultObjectMappingItemCollection)collection, isThreadSafe: true);
break;
}
}
catch (InvalidCastException)
{
throw new MetadataException(Strings.InvalidCollectionForMapping(collection.DataSpace.ToString()));
}
-
- if (existing != null)
- {
- throw new InvalidOperationException(Strings.ItemCollectionAlreadyRegistered(collection.DataSpace.ToString()));
- }
- // Need to make sure that if the storage mapping Item collection was created with the
- // same instances of item collection that are registered for CSpace and SSpace
- if (collection.DataSpace
- == DataSpace.CSpace)
- {
- if (_itemsCSSpace != null
- && !ReferenceEquals(_itemsCSSpace.EdmItemCollection, collection))
- {
- throw new InvalidOperationException(Strings.InvalidCollectionSpecified(collection.DataSpace));
- }
- }
-
- if (collection.DataSpace
- == DataSpace.SSpace)
- {
- if (_itemsCSSpace != null
- && !ReferenceEquals(_itemsCSSpace.StoreItemCollection, collection))
- {
- throw new InvalidOperationException(Strings.InvalidCollectionSpecified(collection.DataSpace));
- }
- }
-
- if (collection.DataSpace
- == DataSpace.CSSpace)
- {
- if (_itemsCSpace != null
- && !ReferenceEquals(_itemsCSSpace.EdmItemCollection, _itemsCSpace))
- {
- throw new InvalidOperationException(Strings.InvalidCollectionSpecified(collection.DataSpace));
- }
-
- if (_itemsSSpace != null
- && !ReferenceEquals(_itemsCSSpace.StoreItemCollection, _itemsSSpace))
- {
- throw new InvalidOperationException(Strings.InvalidCollectionSpecified(collection.DataSpace));
- }
- }
}
/// <summary>
@@ -921,38 +938,6 @@ internal virtual bool TryGetMap(GlobalItem item, DataSpace dataSpace, out Map ma
return (null != collection) && ((MappingItemCollection)collection).TryGetMap(item, out map);
}
- private ItemCollection RegisterDefaultObjectMappingItemCollection()
- {
- if (_itemsCSpace != null
- && _itemsOSpace != null
- && _itemsOCSpace == null)
- {
- lock (_lock)
- {
- if (_itemsOCSpace == null)
- {
- RegisterItemCollection(new DefaultObjectMappingItemCollection(_itemsCSpace, _itemsOSpace));
- }
- }
- }
-
- return _itemsOCSpace;
- }
-
- internal void RegisterDefaultObjectItemCollection()
- {
- if (_itemsOSpace == null)
- {
- lock (_lock)
- {
- if (_itemsOSpace == null)
- {
- RegisterItemCollection(new ObjectItemCollection());
- }
- }
- }
- }
-
/// <summary>
/// Get item collection for the space, if registered. If returned, the ItemCollection is in read only mode as it is
/// part of the workspace.
@@ -983,19 +968,20 @@ internal virtual ItemCollection GetItemCollection(DataSpace dataSpace, bool requ
switch (dataSpace)
{
case DataSpace.CSpace:
- collection = _itemsCSpace;
+ collection = _itemsCSpace == null ? null : _itemsCSpace.Value;
break;
case DataSpace.OSpace:
- collection = _itemsOSpace;
+ Debug.Assert(_itemsOSpace != null);
+ collection = _itemsOSpace.Value;
break;
case DataSpace.OCSpace:
- collection = _itemsOCSpace ?? RegisterDefaultObjectMappingItemCollection();
+ collection = _itemsOCSpace == null ? null : _itemsOCSpace.Value;
break;
case DataSpace.CSSpace:
- collection = _itemsCSSpace;
+ collection = _itemsCSSpace == null ? null : _itemsCSSpace.Value;
break;
case DataSpace.SSpace:
- collection = _itemsSSpace;
+ collection = _itemsSSpace == null ? null : _itemsSSpace.Value;
break;
default:
if (required)
@@ -1318,9 +1304,10 @@ internal virtual bool TryGetFunctionImportMapping(EdmFunction functionImport, ou
/// <returns> </returns>
internal virtual ViewLoader GetUpdateViewLoader()
{
- if (_itemsCSSpace != null)
+ if (_itemsCSSpace != null
+ && _itemsCSSpace.Value != null)
{
- return _itemsCSSpace.GetUpdateViewLoader();
+ return _itemsCSSpace.Value.GetUpdateViewLoader();
}
return null;
}
@@ -1551,8 +1538,8 @@ public virtual IEnumerable<EdmMember> GetRequiredOriginalValueMembers(EntitySetB
/// </summary>
internal virtual QueryCacheManager GetQueryCacheManager()
{
- Debug.Assert(null != _itemsSSpace, "_itemsSSpace must not be null");
- return _itemsSSpace.QueryCacheManager;
+ Debug.Assert(_itemsSSpace != null && _itemsSSpace.Value != null);
+ return _itemsSSpace.Value.QueryCacheManager;
}
internal bool TryDetermineCSpaceModelType<T>(out EdmType modelEdmType)
View
3 src/EntityFramework/Core/Objects/ELinq/CompiledELinqQueryState.cs
@@ -53,9 +53,6 @@ internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption? forMerg
Debug.Assert(Span == null, "Include span specified on compiled LINQ-based ObjectQuery instead of within the expression tree?");
Debug.Assert(_cachedPlan == null, "Cached plan should not be set on compiled LINQ queries");
- // Metadata is required to generate the execution plan or to retrieve it from the cache.
- ObjectContext.EnsureMetadata();
-
ObjectQueryExecutionPlan plan = null;
var cacheEntry = _cacheEntry;
var useCSharpNullComparisonBehavior = ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior;
View
3 src/EntityFramework/Core/Objects/ELinq/ELinqQueryState.cs
@@ -111,9 +111,6 @@ internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption? forMerg
// The plan may have been invalidated above, or this query may never have been prepared.
if (plan == null)
{
- // Metadata is required to generate the execution plan.
- ObjectContext.EnsureMetadata();
-
// Reset internal state
_recompileRequired = null;
ResetParameters();
View
3 src/EntityFramework/Core/Objects/Internal/EntitySqlQueryState.cs
@@ -133,9 +133,6 @@ internal override ObjectQueryState Include<TElementType>(ObjectQuery<TElementTyp
internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption? forMergeOption)
{
- // Metadata is required to generate the execution plan or to retrieve it from the cache.
- ObjectContext.EnsureMetadata();
-
// Determine the required merge option, with the following precedence:
// 1. The merge option specified to Execute(MergeOption) as forMergeOption.
// 2. The merge option set via ObjectQuery.MergeOption.
View
57 src/EntityFramework/Core/Objects/ObjectContext.cs
@@ -220,12 +220,6 @@ protected ObjectContext(EntityConnection connection, string defaultContainerName
Debug.Assert(_workspace != null);
- // register the O-Loader
- _workspace.RegisterDefaultObjectItemCollection();
-
- // have the OC-Loader registered by asking for it
- _workspace.GetItemCollection(DataSpace.OCSpace);
-
// load config file properties
var value = ConfigurationManager.AppSettings[UseLegacyPreserveChangesBehavior];
var useV35Behavior = false;
@@ -1456,9 +1450,6 @@ internal virtual void EnsureConnection()
try
{
- // Make sure the necessary metadata is registered
- EnsureMetadata();
-
var currentTransaction = Transaction.Current;
EnsureContextIsEnlistedInCurrentTransaction(
@@ -1514,9 +1505,6 @@ internal virtual void EnsureConnection()
try
{
- // Make sure the necessary metadata is registered
- EnsureMetadata();
-
var currentTransaction = Transaction.Current;
await EnsureContextIsEnlistedInCurrentTransaction(
@@ -1689,42 +1677,6 @@ internal virtual void ReleaseConnection()
}
}
- internal virtual void EnsureMetadata()
- {
- if (!MetadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
- {
- Debug.Assert(
- !MetadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace), "ObjectContext has C-S metadata but not S?");
-
- // Only throw an ObjectDisposedException if an attempt is made to access the underlying connection object.
- if (_disposed)
- {
- throw new ObjectDisposedException(null, Strings.ObjectContext_ObjectDisposed);
- }
-
- var connectionWorkspace = ((EntityConnection)Connection).GetMetadataWorkspace();
-
- Debug.Assert(
- connectionWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace) &&
- connectionWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace) &&
- connectionWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace),
- "EntityConnection.GetMetadataWorkspace() did not return an initialized workspace?");
-
- // Validate that the context's MetadataWorkspace and the underlying connection's MetadataWorkspace
- // have the same CSpace collection. Otherwise, an error will occur when trying to set the SSpace
- // and CSSpace metadata
- var connectionCSpaceCollection = connectionWorkspace.GetItemCollection(DataSpace.CSpace);
- var contextCSpaceCollection = MetadataWorkspace.GetItemCollection(DataSpace.CSpace);
- if (!ReferenceEquals(connectionCSpaceCollection, contextCSpaceCollection))
- {
- throw new InvalidOperationException(Strings.ObjectContext_MetadataHasChanged);
- }
-
- MetadataWorkspace.RegisterItemCollection(connectionWorkspace.GetItemCollection(DataSpace.SSpace));
- MetadataWorkspace.RegisterItemCollection(connectionWorkspace.GetItemCollection(DataSpace.CSSpace));
- }
- }
-
#endregion
/// <summary>
@@ -1791,10 +1743,7 @@ private MetadataWorkspace RetrieveMetadataWorkspaceFromConnection()
throw new ObjectDisposedException(null, Strings.ObjectContext_ObjectDisposed);
}
- var connectionWorkspace = ((EntityConnection)Connection).GetMetadataWorkspace(initializeAllCollections: false);
- Debug.Assert(connectionWorkspace != null, "EntityConnection.MetadataWorkspace is null.");
-
- return connectionWorkspace;
+ return _connection.GetMetadataWorkspace();
}
/// <summary>
@@ -3870,10 +3819,6 @@ public virtual ObjectResult<TEntity> Translate<TEntity>(DbDataReader reader, str
entitySet = GetEntitySetFromName(entitySetName);
}
- // make sure all metadata is available (normally this is handled by the call to EntityConnection.Open,
- // but translate does not necessarily use the EntityConnection)
- EnsureMetadata();
-
// get the expected EDM type
EdmType modelEdmType;
var unwrappedTElement = Nullable.GetUnderlyingType(typeof(TElement)) ?? typeof(TElement);
View
1 src/EntityFramework/Core/Objects/ObjectQuery.cs
@@ -204,7 +204,6 @@ public string ToTraceString()
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public TypeUsage GetResultType()
{
- Context.EnsureMetadata();
if (null == _resultType)
{
// Retrieve the result type from the implementation, in terms of C-Space.
View
1 src/EntityFramework/Core/Objects/ObjectViewFactory.cs
@@ -267,7 +267,6 @@ private static TypeUsage GetOSpaceTypeUsage(TypeUsage typeUsage, ObjectContext o
}
else
{
- objectContext.EnsureMetadata();
ospaceTypeUsage = objectContext.Perspective.MetadataWorkspace.GetOSpaceTypeUsage(typeUsage);
}
}
View
24 src/EntityFramework/ModelConfiguration/Edm/DbDatabaseMappingExtensions.cs
@@ -35,22 +35,14 @@ public static MetadataWorkspace ToMetadataWorkspace(this DbDatabaseMapping datab
{
DebugCheck.NotNull(databaseMapping);
- var metadataWorkspace = new MetadataWorkspace();
-
- var itemCollection
- = new EdmItemCollection(databaseMapping.Model);
-
- var storeItemCollection
- = new StoreItemCollection(databaseMapping.Database);
-
- var storageMappingItemCollection
- = databaseMapping.ToStorageMappingItemCollection(itemCollection, storeItemCollection);
-
- metadataWorkspace.RegisterItemCollection(itemCollection);
- metadataWorkspace.RegisterItemCollection(storeItemCollection);
- metadataWorkspace.RegisterItemCollection(storageMappingItemCollection);
-
- return metadataWorkspace;
+ var itemCollection = new EdmItemCollection(databaseMapping.Model);
+ var storeItemCollection = new StoreItemCollection(databaseMapping.Database);
+ var storageMappingItemCollection = databaseMapping.ToStorageMappingItemCollection(itemCollection, storeItemCollection);
+
+ return new MetadataWorkspace(
+ () => itemCollection,
+ () => storeItemCollection,
+ () => storageMappingItemCollection);
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
View
9 src/EntityFramework/Properties/Resources.cs
@@ -4526,14 +4526,6 @@ internal static string AssemblyMissingFromAssembliesToConsider(object p0)
}
/// <summary>
- /// A string like "Item Collection for '{0}' is not valid. Make sure that the StorageMappingItemCollection was constructed with the same instances of item collection that are registered for conceptual model and storage model."
- /// </summary>
- internal static string InvalidCollectionSpecified(object p0)
- {
- return EntityRes.GetString(EntityRes.InvalidCollectionSpecified, p0);
- }
-
- /// <summary>
/// A string like "Unable to load the specified metadata resource."
/// </summary>
internal static string UnableToLoadResource
@@ -15912,7 +15904,6 @@ internal sealed class EntityRes
internal const string InvalidUseOfWebPath = "InvalidUseOfWebPath";
internal const string UnableToFindReflectedType = "UnableToFindReflectedType";
internal const string AssemblyMissingFromAssembliesToConsider = "AssemblyMissingFromAssembliesToConsider";
- internal const string InvalidCollectionSpecified = "InvalidCollectionSpecified";
internal const string UnableToLoadResource = "UnableToLoadResource";
internal const string EdmVersionNotSupportedByRuntime = "EdmVersionNotSupportedByRuntime";
internal const string AtleastOneSSDLNeeded = "AtleastOneSSDLNeeded";
View
3 src/EntityFramework/Properties/Resources.resx
@@ -1971,9 +1971,6 @@
<data name="AssemblyMissingFromAssembliesToConsider" xml:space="preserve">
<value>The assembly '{0}' specified does not exist in the assemblies enumeration.</value>
</data>
- <data name="InvalidCollectionSpecified" xml:space="preserve">
- <value>Item Collection for '{0}' is not valid. Make sure that the StorageMappingItemCollection was constructed with the same instances of item collection that are registered for conceptual model and storage model.</value>
- </data>
<data name="UnableToLoadResource" xml:space="preserve">
<value>Unable to load the specified metadata resource.</value>
</data>
View
139 test/EntityFramework/FunctionalTests.Transitional/MetadataMapping/EnumOCMappingTests.cs
@@ -1,15 +1,13 @@
-
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
+
namespace System.Data.Entity.MetadataMapping
{
using System.Data.Entity.Core;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Resources;
- using System.Data.Entity.TestHelpers;
- using System.IO;
using System.Linq;
using System.Reflection;
- using System.Xml;
using System.Xml.Linq;
using Xunit;
@@ -22,6 +20,7 @@ private static XDocument EnumCsdl()
.GetExecutingAssembly()
.GetManifestResourceStream("System.Data.Entity.MetadataMapping.Enum.csdl"));
}
+
#region convention loader (POCO)
[Fact]
@@ -68,7 +67,6 @@ public void Cannot_map_OSpace_enum_type_with_unsupported_underlying_type_POCO()
Assert.Contains(
Strings.Validator_UnsupportedEnumUnderlyingType("System.UInt32"),
exception.Message);
-
}
[Fact]
@@ -114,8 +112,8 @@ public void Cannot_map_OSpace_enum_type_with_fewer_members_than_CSpace_enum_type
public void Cannot_map_OSpace_enum_type_whose_member_name_does_not_match_CSpace_enum_type_member_name_POCO()
{
var exception = Assert.Throws<MetadataException>(
- () =>
- Cannot_map_OSpace_enum_type_whose_member_name_does_not_match_CSpace_enum_type_member_name(true));
+ () =>
+ Cannot_map_OSpace_enum_type_whose_member_name_does_not_match_CSpace_enum_type_member_name(true));
Assert.Contains(
Strings.Validator_OSpace_Convention_MissingOSpaceType("MessageModel.MessageType"),
@@ -142,8 +140,8 @@ public void Can_map_CSpace_enum_type_with_no_enum_members_POCO()
public void Cannot_map_if_OSpace_enum_type_member_value_does_not_match_CSpace_enum_type_member_value_POCO()
{
var exception = Assert.Throws<MetadataException>(
- () =>
- Cannot_map_if_OSpace_enum_type_member_value_does_not_match_CSpace_enum_type_member_value(true));
+ () =>
+ Cannot_map_if_OSpace_enum_type_member_value_does_not_match_CSpace_enum_type_member_value(true));
Assert.Contains(
Strings.Validator_OSpace_Convention_MissingOSpaceType("MessageModel.MessageType"),
@@ -178,7 +176,7 @@ public void Verify_OSpace_entity_type_is_not_mapped_to_CSpace_enum_type_with_sam
public void Correct_CSpace_enum_type_is_mapped_if_multiple_OSpace_enum_types_exist_but_only_one_matches()
{
var additionalEnumType = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""MessageModel1"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""MessageModel1"">
<EnumType Name=""MessageType"" IsFlags=""false"" />
</Schema>");
@@ -201,7 +199,7 @@ public void Correct_CSpace_enum_type_is_mapped_if_multiple_OSpace_enum_types_exi
public void Mapping_fails_for_multiple_OSpace_enum_types_matching_the_same_CSpace_enum_type_POCO()
{
var additionalMatchingEnumType = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""MessageModel1"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""MessageModel1"">
<EnumType Name=""MessageType"" IsFlags=""false"">
<Member Name=""Express"" />
<Member Name=""Priority"" />
@@ -266,12 +264,12 @@ public void Can_load_entity_with_property_of_enum_type_from_different_assembly()
const bool isPOCO = true;
var enumTypeCsdl = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""EnumModel"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""EnumModel"">
<EnumType Name=""Enum"" IsFlags=""false"" />
</Schema>");
var entityTypeCsdl = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""EnumModel"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""EnumModel"">
<EntityContainer Name=""EnumModelContainer"">
<EntitySet Name=""Entity"" EntityType=""EnumModel.Entity"" />
</EntityContainer>
@@ -288,29 +286,31 @@ public void Can_load_entity_with_property_of_enum_type_from_different_assembly()
var assemblyWithEntityType = BuildAssembly(isPOCO, entityTypeCsdl);
EdmItemCollection edmItemCollection;
-
- var workspace = new MetadataWorkspace();
using (var enumTypeReader = enumTypeCsdl.CreateReader())
- using (var entityTypeReader = entityTypeCsdl.CreateReader())
{
- edmItemCollection =
- new EdmItemCollection(
- new XmlReader[] { enumTypeReader, entityTypeReader });
+ using (var entityTypeReader = entityTypeCsdl.CreateReader())
+ {
+ edmItemCollection =
+ new EdmItemCollection(
+ new[] { enumTypeReader, entityTypeReader });
+ }
}
- workspace.RegisterItemCollection(edmItemCollection);
var objectItemCollection = new ObjectItemCollection();
-
objectItemCollection.LoadFromAssembly(assemblyWithEnumType, edmItemCollection);
objectItemCollection.LoadFromAssembly(assemblyWithEntityType, edmItemCollection);
- workspace.RegisterItemCollection(objectItemCollection);
+
+ var workspace = new MetadataWorkspace(
+ () => edmItemCollection,
+ () => null,
+ () => null,
+ () => objectItemCollection);
Assert.Equal(
"EnumModel.Entity:EnumModel.Entity",
workspace.GetMap("EnumModel.Entity", DataSpace.OSpace, DataSpace.OCSpace).Identity);
}
-
#endregion
#region attribute loader (non-POCO)
@@ -362,7 +362,6 @@ public void Cannot_map_OSpace_enum_type_with_unsupported_underlying_NonPOCO()
Assert.Contains(
Strings.Validator_UnsupportedEnumUnderlyingType("System.UInt32"),
exception.Message);
-
}
[Fact]
@@ -372,14 +371,14 @@ public void Cannot_map_enum_types_if_names_are_different_NonPOCO()
Strings.Mapping_Object_InvalidType("MessageModel.ShippingType"),
Assert.Throws<InvalidOperationException>(
() => Cannot_map_enum_types_if_names_are_different(false)).Message);
-
}
[Fact]
public void OSpaceEnumUnderlyingTypeDoesNotMatchCSpaceEnumUnderlyingTypeName_NonPOCO()
{
Assert.Contains(
- Strings.Mapping_Enum_OCMapping_UnderlyingTypesMismatch("Int32", "MessageModel.MessageType", "Int64", "MessageModel.MessageType"),
+ Strings.Mapping_Enum_OCMapping_UnderlyingTypesMismatch(
+ "Int32", "MessageModel.MessageType", "Int64", "MessageModel.MessageType"),
Assert.Throws<MappingException>(
() => Cannot_map_enum_types_if_underlying_types_dont_match(false)).Message);
}
@@ -466,7 +465,7 @@ public void EnumTypeVerifiedWhenLoadingEntityWithPropertyOfThisEnumType_NonPOCO(
"MessageModel.MessageType"),
Assert.Throws<MappingException>(
() =>
- GetMappedType(oSpaceCsdl, EnumCsdl(), "MessageModel.Message", false)).Message);
+ GetMappedType(oSpaceCsdl, EnumCsdl(), "MessageModel.Message", false)).Message);
}
[Fact]
@@ -478,9 +477,9 @@ public void Can_use_EdmEnumType_attribute_to_map_OSpace_enum_type_to_CSpace_enum
.SetAttributeValue("Namespace", "MessageModelModified");
foreach (var attribute in cSpaceCsdl
- .Descendants()
- .Attributes()
- .Where(a => ((string)a).StartsWith("MessageModel.")))
+ .Descendants()
+ .Attributes()
+ .Where(a => ((string)a).StartsWith("MessageModel.")))
{
attribute.SetValue(((string)attribute).Replace("MessageModel.", "MessageModelModified."));
}
@@ -491,19 +490,18 @@ public void Can_use_EdmEnumType_attribute_to_map_OSpace_enum_type_to_CSpace_enum
.SetAttributeValue("Name", "NewMessageType");
foreach (var propertyElement in cSpaceCsdl
- .Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}Property")
- .Where(p => (string)p.Attribute("Type") == "MessageModelModified.MessageType"))
+ .Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}Property")
+ .Where(p => (string)p.Attribute("Type") == "MessageModelModified.MessageType"))
{
propertyElement.SetAttributeValue("Type", "MessageModelModified.NewMessageType");
}
-
var oSpaceCsdl = EnumCsdl();
foreach (var typeElement in oSpaceCsdl
- .Element("{http://schemas.microsoft.com/ado/2009/11/edm}Schema")
- .Elements()
- .Where(e => new string[] { "EntityType", "ComplexType", "EnumType" }.Contains(e.Name.LocalName)))
+ .Element("{http://schemas.microsoft.com/ado/2009/11/edm}Schema")
+ .Elements()
+ .Where(e => new[] { "EntityType", "ComplexType", "EnumType" }.Contains(e.Name.LocalName)))
{
if ((string)typeElement.Attribute("Name") == "MessageType")
{
@@ -568,14 +566,15 @@ public void Cannot_have_2_OSpace_enum_types_mapped_to_single_CSpace_enum_type()
var enumTypeElement =
additionalMatchingEnumType.
Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}EnumType")
- .Single();
+ .Single();
enumTypeElement.SetAttributeValue("{MappingTestExtension}OSpaceTypeName", "MessageType");
enumTypeElement.SetAttributeValue("{MappingTestExtension}OSpaceTypeNamespace", "MessageModel");
Assert.Equal(
Strings.Mapping_CannotMapCLRTypeMultipleTimes("MessageModel.MessageType"),
- Assert.Throws<MappingException>(() =>
+ Assert.Throws<MappingException>(
+ () =>
CreateMetadataWorkspace(
EnumCsdl(),
BuildAssembly(false, EnumCsdl(), additionalMatchingEnumType),
@@ -586,7 +585,7 @@ public void Cannot_have_2_OSpace_enum_types_mapped_to_single_CSpace_enum_type()
private static void Verify_simple_enum_mapping(bool isPOCO)
{
- var workspace = PrepareModel(/* oSpaceCsdl */ EnumCsdl(), /* cSpaceCsdl */ EnumCsdl(), isPOCO);
+ var workspace = PrepareModel( /* oSpaceCsdl */ EnumCsdl(), /* cSpaceCsdl */ EnumCsdl(), isPOCO);
Assert.Equal(
"MessageModel.MessageType:MessageModel.MessageType",
@@ -600,7 +599,7 @@ private static void Verify_simple_enum_mapping(bool isPOCO)
private static void Complex_type_with_enum_property_is_mapped_correctly(bool isPOCO)
{
var complexType = XElement.Parse(
-@"<ComplexType Name=""Complex"" xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"">
+ @"<ComplexType Name=""Complex"" xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"">
<Property Name=""MessageType"" Type=""MessageModel.MessageType"" Nullable=""false""/>
</ComplexType>");
@@ -613,12 +612,14 @@ private static void Complex_type_with_enum_property_is_mapped_correctly(bool isP
csdl
.Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}EntityType")
.Single(e => (string)e.Attribute("Name") == "Message")
- .Add(new XElement("{http://schemas.microsoft.com/ado/2009/11/edm}Property",
- new XAttribute("Name", "ComplexProperty"),
- new XAttribute("Type", "MessageModel.Complex"),
- new XAttribute("Nullable", "false")));
+ .Add(
+ new XElement(
+ "{http://schemas.microsoft.com/ado/2009/11/edm}Property",
+ new XAttribute("Name", "ComplexProperty"),
+ new XAttribute("Type", "MessageModel.Complex"),
+ new XAttribute("Nullable", "false")));
- var workspace = PrepareModel(/* oSpaceCsdl */ csdl, /* cSpaceCsdl */ csdl, isPOCO);
+ var workspace = PrepareModel( /* oSpaceCsdl */ csdl, /* cSpaceCsdl */ csdl, isPOCO);
Assert.Equal(
"MessageModel.MessageType:MessageModel.MessageType",
@@ -640,9 +641,11 @@ private static void Enums_with_members_with_same_values_are_mapped_even_if_order
.Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}EnumType")
.Single(e => (string)e.Attribute("Name") == "ContentsType");
- oSpaceEnumType.Add(new XElement("{http://schemas.microsoft.com/ado/2009/11/edm}Member",
- new XAttribute("Name", "LegacyType"),
- new XAttribute("Value", 0)));
+ oSpaceEnumType.Add(
+ new XElement(
+ "{http://schemas.microsoft.com/ado/2009/11/edm}Member",
+ new XAttribute("Name", "LegacyType"),
+ new XAttribute("Value", 0)));
var cSpaceCsdl = new XDocument(oSpaceCsdl);
var cSpaceEnumType = cSpaceCsdl
@@ -769,12 +772,14 @@ private static void Can_map_OSpace_enum_type_that_has_more_members_than_CSPace_e
var oSpaceCsdl = EnumCsdl();
var enumType = oSpaceCsdl
- .Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}EnumType")
- .Single(e => (string)e.Attribute("Name") == "MessageType");
+ .Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}EnumType")
+ .Single(e => (string)e.Attribute("Name") == "MessageType");
- enumType.Add(new XElement("{http://schemas.microsoft.com/ado/2009/11/edm}Member",
- new XAttribute("Name", "LegacyType"),
- new XAttribute("Value", 0)));
+ enumType.Add(
+ new XElement(
+ "{http://schemas.microsoft.com/ado/2009/11/edm}Member",
+ new XAttribute("Name", "LegacyType"),
+ new XAttribute("Value", 0)));
Assert.Equal(
"MessageModel.Message:MessageModel.Message",
@@ -786,10 +791,10 @@ private static void Can_map_CSpace_enum_type_with_no_enum_members(bool isPOCO)
var cSpaceCsdl = EnumCsdl();
cSpaceCsdl
- .Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}EnumType")
- .Single(e => (string)e.Attribute("Name") == "MessageType")
- .Elements()
- .Remove();
+ .Descendants("{http://schemas.microsoft.com/ado/2009/11/edm}EnumType")
+ .Single(e => (string)e.Attribute("Name") == "MessageType")
+ .Elements()
+ .Remove();
Assert.Equal(
"MessageModel.Message:MessageModel.Message",
@@ -811,12 +816,12 @@ private static void Cannot_map_if_OSpace_enum_type_member_value_does_not_match_C
private static void OSpace_enum_type_and_CSpace_entity_type_have_the_same_name(bool isPOCO)
{
var oSpaceCsdl = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
<EnumType Name=""MessageType"" IsFlags=""false"" />
</Schema>");
var cSpaceCsdl = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
<EntityType Name=""MessageType"">
<Key>
<PropertyRef Name=""Id"" />
@@ -831,7 +836,7 @@ private static void OSpace_enum_type_and_CSpace_entity_type_have_the_same_name(b
private static void OSpace_entity_type_and_CSpace_enum_type_have_the_same_name(bool isPOCO)
{
var oSpaceCsdl = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
<EntityType Name=""MessageType"">
<Key>
<PropertyRef Name=""Id"" />
@@ -841,7 +846,7 @@ private static void OSpace_entity_type_and_CSpace_enum_type_have_the_same_name(b
</Schema>");
var cSpaceCsdl = XDocument.Parse(
-@"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
+ @"<Schema xmlns=""http://schemas.microsoft.com/ado/2009/11/edm"" Namespace=""Model"">
<EnumType Name=""MessageType"" IsFlags=""false"" />
</Schema>");
@@ -871,16 +876,12 @@ private static MetadataWorkspace PrepareModel(XDocument oSpaceCsdl, XDocument cS
private static MetadataWorkspace CreateMetadataWorkspace(XDocument cSpaceCsdl, Assembly assembly, bool isPOCO)
{
- var workspace = new MetadataWorkspace();
EdmItemCollection edmItemCollection;
-
using (var csdlReader = cSpaceCsdl.CreateReader())
{
- edmItemCollection = new EdmItemCollection(new XmlReader[] { csdlReader });
+ edmItemCollection = new EdmItemCollection(new[] { csdlReader });
}
- workspace.RegisterItemCollection(edmItemCollection);
-
// assembly can actually be an AssemblyBuilder. The following line ensures that we are
// using the actual assembly otherwise an Assert in ObjectItemAttributeAssemblyLoader.LoadType
@@ -897,7 +898,11 @@ private static MetadataWorkspace CreateMetadataWorkspace(XDocument cSpaceCsdl, A
objectItemCollection.LoadFromAssembly(assembly);
}
- workspace.RegisterItemCollection(objectItemCollection);
+ var workspace = new MetadataWorkspace(
+ () => edmItemCollection,
+ () => null,
+ () => null,
+ () => objectItemCollection);
return workspace;
}
View
41 test/EntityFramework/FunctionalTests.Transitional/TestHelpers/TestBase.cs
@@ -76,6 +76,47 @@ protected static DataRow CreateProviderRow(string name, string invariantName, st
return row;
}
+ protected static void RunTestWithTempMetadata(string csdl, string ssdl, string msl, Action<IEnumerable<string>> test)
+ {
+ var paths = new[]
+ {
+ Path.GetTempFileName() + ".ssdl",
+ Path.GetTempFileName() + ".csdl",
+ Path.GetTempFileName() + ".msl"
+ };
+ var metadata = new[]
+ {
+ ssdl,
+ csdl,
+ msl
+ };
+ try
+ {
+ for (var i = 0; i < metadata.Length; i++)
+ {
+ using (var file = File.CreateText(paths[i]))
+ {
+ file.Write(metadata[i]);
+ }
+ }
+ test(paths);
+ }
+ finally
+ {
+ foreach (var path in paths)
+ {
+ try
+ {
+ File.SetAttributes(path, File.GetAttributes(path) & ~FileAttributes.ReadOnly);
+ File.Delete(path);
+ }
+ catch (FileNotFoundException)
+ {
+ }
+ }
+ }
+ }
+
#region Assemblies and exceptions
/// <summary>
View
36 test/EntityFramework/FunctionalTests/ProductivityApi/ConnectionTests.cs
@@ -2,12 +2,12 @@
namespace ProductivityApiTests
{
- using System;
using System.Data;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Core;
using System.Data.Entity.Core.EntityClient;
+ using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
@@ -134,6 +134,21 @@ public void EntitConnection_object_with_empty_context_can_be_used_to_create_cont
}
[Fact]
+ public void GetMetadataWorkspace_returns_an_initialized_workspace_when_connection_string_constructor_is_used()
+ {
+ using (var connection = new EntityConnection(SimpleModelEntityConnectionString))
+ {
+ var workspace = connection.GetMetadataWorkspace();
+
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.OSpace));
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.OCSpace));
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.SSpace));
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.CSSpace));
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.CSpace));
+ }
+ }
+
+ [Fact]
public void Context_name_can_be_used_to_find_entity_connection_string_in_app_config()
{
using (var context = new EntityConnectionForSimpleModel())
@@ -183,13 +198,13 @@ private void Existing_connection_is_same_state_it_started_in_after_use(Connectio
var opened = false;
connection.StateChange += (_, e) =>
- {
- if (e.CurrentState
- == ConnectionState.Open)
- {
- opened = true;
- }
- };
+ {
+ if (e.CurrentState
+ == ConnectionState.Open)
+ {
+ opened = true;
+ }
+ };
using (var context = new SimpleModelContext(connection))
{
@@ -885,8 +900,9 @@ public void Useful_exception_is_thrown_if_model_creation_happens_with_bad_MVC4_c
{
try
{
- MutableResolver.AddResolver<IDbConnectionFactory>(k => new SqlConnectionFactory(
- "Data Source=(localdb)\v11.0; Integrated Security=True; Connection Timeout=1;"));
+ MutableResolver.AddResolver<IDbConnectionFactory>(
+ k => new SqlConnectionFactory(
+ "Data Source=(localdb)\v11.0; Integrated Security=True; Connection Timeout=1;"));
using (var context = new BadMvcContext())
{
View
28 test/EntityFramework/FunctionalTests/ProductivityApi/MultiThreadingTests.cs
@@ -6,6 +6,7 @@ namespace ProductivityApiTests
using System.Collections.Concurrent;
using System.Data.Entity;
using System.Data.Entity.Core;
+ using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
using System.Linq;
@@ -186,6 +187,33 @@ public void A_context_type_can_go_through_initialization_and_be_used_for_CRUD_fr
});
}
+ public class SimpleModelContextForThreads : SimpleModelContext
+ {
+ public SimpleModelContextForThreads()
+ : base(SimpleModelEntityConnectionString)
+ {
+ }
+ }
+
+ [Fact]
+ public void EDMX_based_DbContext_initialization_should_work_when_called_concurrently_from_multiple_threads()
+ {
+ ExecuteInParallel(
+ () =>
+ {
+ using (var context = new SimpleModelContextForThreads())
+ {
+ context.Products.ToString(); // Causes s-space and c/s loading
+
+ var workspace = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.OCSpace));
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.CSSpace));
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.SSpace));
+ Assert.NotNull(workspace.GetItemCollection(DataSpace.CSpace));
+ }
+ });
+ }
+
#endregion
#region WriteEdmx
View
51 test/EntityFramework/UnitTests/Core/Common/CommandTrees/DbCommandTreeTests.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
+
+namespace System.Data.Entity.Core.Common.CommandTrees
+{
+ using System.Collections.Generic;
+ using System.Data.Entity.Core.Common.CommandTrees.Internal;
+ using System.Data.Entity.Core.Metadata.Edm;
+ using Moq;
+ using Xunit;
+
+ public class DbCommandTreeTests : TestBase
+ {
+ public class ConcreteDbCommandTree : DbCommandTree
+ {
+ public ConcreteDbCommandTree(MetadataWorkspace workspace, DataSpace dataSpace)
+ : base(workspace, dataSpace)
+ {
+ }
+
+ public override DbCommandTreeKind CommandTreeKind
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ internal override IEnumerable<KeyValuePair<string, TypeUsage>> GetParameters()
+ {
+ throw new NotImplementedException();
+ }
+
+ internal override void DumpStructure(ExpressionDumper dumper)
+ {
+ throw new NotImplementedException();
+ }
+
+ internal override string PrintTree(ExpressionPrinter printer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [Fact]
+ public void Data_space_and_workspace_are_set_from_constructor()
+ {
+ var workspace = new Mock<MetadataWorkspace>().Object;
+ var tree = new ConcreteDbCommandTree(workspace, DataSpace.CSpace);
+
+ Assert.Same(workspace, tree.MetadataWorkspace);
+ Assert.Equal(DataSpace.CSpace, tree.DataSpace);
+ }
+ }
+}
View
133 test/EntityFramework/UnitTests/Core/EntityClient/EntityConnectionTests.cs
@@ -6,18 +6,56 @@ namespace System.Data.Entity.Core.EntityClient
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Resources;
+ using System.Data.SqlClient;
using System.Linq;
using System.Transactions;
using Moq;
using Moq.Protected;
using Xunit;
+ using IsolationLevel = System.Data.IsolationLevel;
+
#if !NET40
using System.Threading;
using System.Threading.Tasks;
#endif
public class EntityConnectionTests
{
+ public class Constructors : TestBase
+ {
+ [Fact]
+ public void EntityConnection_worksapce_constructors_check_arguments()
+ {
+ Assert.Equal(
+ "workspace",
+ Assert.Throws<ArgumentNullException>(() => new EntityConnection(null, new Mock<DbConnection>().Object)).ParamName);
+ Assert.Equal(
+ "connection",
+ Assert.Throws<ArgumentNullException>(() => new EntityConnection(new Mock<MetadataWorkspace>().Object, null)).ParamName);
+ Assert.Equal(
+ "workspace",
+ Assert.Throws<ArgumentNullException>(() => new EntityConnection(null, new Mock<DbConnection>().Object, true)).ParamName);
+ Assert.Equal(
+ "connection",
+ Assert.Throws<ArgumentNullException>(() => new EntityConnection(new Mock<MetadataWorkspace>().Object, null, true)).ParamName);
+ }
+ }
+
+ public class GetMetadataWorkspace : TestBase
+ {
+ [Fact]
+ public void GetMetadataWorkspace_returns_the_workspace_passed_to_constructor()
+ {
+ var mockWorkspace = new Mock<MetadataWorkspace>();
+ mockWorkspace.Setup(m => m.IsItemCollectionAlreadyRegistered(It.IsAny<DataSpace>())).Returns(true);
+ mockWorkspace.Setup(m => m.GetItemCollection(DataSpace.SSpace)).Returns(new Mock<StoreItemCollection>().Object);
+
+ Assert.Same(mockWorkspace.Object, new EntityConnection(mockWorkspace.Object, new SqlConnection()).GetMetadataWorkspace());
+ Assert.Same(
+ mockWorkspace.Object, new EntityConnection(mockWorkspace.Object, new SqlConnection(), true).GetMetadataWorkspace());
+ }
+ }
+
public class Open : TestBase
{
[Fact]
@@ -123,60 +161,41 @@ public void Exception_is_thrown_when_store_connection_doesnt_open()
}
[Fact]
- public void Underlying_dbConnection_is_being_closed_if_it_was_initially_closed_and_metadata_initialization_fails()
- {
- var dbConnectionState = ConnectionState.Closed;
- var dbConnectionMock = new Mock<DbConnection>(MockBehavior.Strict);
- dbConnectionMock.Setup(m => m.Open()).Callback(() => dbConnectionState = ConnectionState.Open);
- dbConnectionMock.Setup(m => m.Close()).Verifiable();
- dbConnectionMock.SetupGet(m => m.State).Returns(() => dbConnectionState);
- dbConnectionMock.SetupGet(m => m.DataSource).Returns(() => "foo");
-
- var metadataWorkspaceMock = new Mock<MetadataWorkspace>(MockBehavior.Strict);
- metadataWorkspaceMock.Setup(m => m.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)).Throws<InvalidOperationException>();
- var metadataWorkspace = metadataWorkspaceMock.Object;
- var entityConnection = new EntityConnection(metadataWorkspace, dbConnectionMock.Object, true, true);
-
- Assert.Throws<InvalidOperationException>(() => entityConnection.Open());
-
- dbConnectionMock.Verify(m => m.Close(), Times.Once());
- }
-
- [Fact]
- public void Underlying_dbConnection_is_not_being_closed_if_it_was_initially_opened_and_metadata_initialization_fails()
+ public void Underlying_dbConnection_is_not_being_closed_if_it_was_initially_opened_such_that_it_cannot_be_reopend()
{
var dbConnectionMock = new Mock<DbConnection>(MockBehavior.Strict);
dbConnectionMock.Setup(m => m.Open()).Verifiable();
dbConnectionMock.Setup(m => m.Close()).Verifiable();
dbConnectionMock.SetupGet(m => m.State).Returns(ConnectionState.Open);
dbConnectionMock.SetupGet(m => m.DataSource).Returns(() => "foo");
- var metadataWorkspaceMock = new Mock<MetadataWorkspace>(MockBehavior.Strict);
- metadataWorkspaceMock.Setup(m => m.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)).Throws<InvalidOperationException>();
- var metadataWorkspace = (metadataWorkspaceMock.Object);
- var entityConnection = new EntityConnection(metadataWorkspace, dbConnectionMock.Object, true, true);
+ var entityConnection = new EntityConnection(
+ new Mock<MetadataWorkspace>(MockBehavior.Strict).Object, dbConnectionMock.Object, true, true);
- Assert.Throws<InvalidOperationException>(() => entityConnection.Open());
+ Assert.Equal(
+ Strings.EntityClient_CannotReopenConnection,
+ Assert.Throws<InvalidOperationException>(() => entityConnection.Open()).Message);
dbConnectionMock.Verify(m => m.Close(), Times.Never());
Assert.Equal(ConnectionState.Open, entityConnection.StoreConnection.State);
}
[Fact]
- public void EntityConnection_with_closed_underlying_connection_maintains_closed_if_metadata_initialization_fails()
+ public void EntityConnection_with_closed_underlying_connection_maintains_closed_if_store_connection_does_not_open_correctly()
{
var dbConnectionMock = new Mock<DbConnection>(MockBehavior.Strict);
dbConnectionMock.Setup(m => m.Open()).Verifiable();
dbConnectionMock.Setup(m => m.Close()).Verifiable();
dbConnectionMock.SetupGet(m => m.State).Returns(ConnectionState.Closed);
dbConnectionMock.SetupGet(m => m.DataSource).Returns(() => "foo");
- var metadataWorkspaceMock = new Mock<MetadataWorkspace>(MockBehavior.Strict);
- metadataWorkspaceMock.Setup(m => m.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)).Throws<InvalidOperationException>();
- var entityConnection = new EntityConnection(metadataWorkspaceMock.Object, dbConnectionMock.Object, true, true);
+ var entityConnection = new EntityConnection(
+ new Mock<MetadataWorkspace>(MockBehavior.Strict).Object, dbConnectionMock.Object, true, true);
- Assert.Throws<InvalidOperationException>(() => entityConnection.Open());
+ Assert.Equal(
+ Strings.EntityClient_ConnectionNotOpen,
+ Assert.Throws<InvalidOperationException>(() => entityConnection.Open()).Message);
Assert.Equal(ConnectionState.Closed, entityConnection.State);
}
@@ -621,42 +640,23 @@ public void Exception_is_thrown_when_store_connection_doesnt_open()
}
[Fact]
- public void Underlying_dbConnection_is_being_closed_if_it_was_initially_closed_and_metadata_initialization_fails()
- {
- var dbConnectionState = ConnectionState.Closed;
- var dbConnectionMock = new Mock<DbConnection>();
- dbConnectionMock.Setup(m => m.OpenAsync(It.IsAny<CancellationToken>())).Callback(
- () => dbConnectionState = ConnectionState.Open).Returns(Task.FromResult(1));
- dbConnectionMock.Setup(m => m.Close()).Verifiable();
- dbConnectionMock.SetupGet(m => m.State).Returns(() => dbConnectionState);
- dbConnectionMock.SetupGet(m => m.DataSource).Returns("fake");
-
- var metadataWorkspaceMock = new Mock<MetadataWorkspace>(MockBehavior.Strict);
- metadataWorkspaceMock.Setup(m => m.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)).Throws<InvalidOperationException>();
- var entityConnection = new EntityConnection(metadataWorkspaceMock.Object, dbConnectionMock.Object, true, true);
-
- AssertThrowsInAsyncMethod<InvalidOperationException>(null, () => entityConnection.OpenAsync().Wait());
-
- dbConnectionMock.Verify(m => m.Close(), Times.Once());
- }
-
- [Fact]
- public void Underlying_dbConnection_is_not_being_closed_if_it_was_initially_open_and_metadata_initialization_fails()
+ public void Underlying_dbConnection_is_not_being_closed_if_it_was_initially_open_such_that_it_cannot_be_reopend()
{
var dbConnectionMock = new Mock<DbConnection>(MockBehavior.Strict);
dbConnectionMock.Setup(m => m.OpenAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(1));
dbConnectionMock.Setup(m => m.Close()).Verifiable();
dbConnectionMock.SetupGet(m => m.State).Returns(ConnectionState.Open);
dbConnectionMock.SetupGet(m => m.DataSource).Returns("fake");
- var metadataWorkspaceMock = new Mock<MetadataWorkspace>(MockBehavior.Strict);
- metadataWorkspaceMock.Setup(m => m.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)).Throws<InvalidOperationException>();
- var entityConnection = new EntityConnection(metadataWorkspaceMock.Object, dbConnectionMock.Object, true, true);
+ var entityConnection = new EntityConnection(
+ new Mock<MetadataWorkspace>(MockBehavior.Strict).Object, dbConnectionMock.Object, true, true);
Assert.Equal(ConnectionState.Open, entityConnection.State);
Assert.Equal(ConnectionState.Open, entityConnection.StoreConnection.State);
- AssertThrowsInAsyncMethod<InvalidOperationException>(null, () => entityConnection.OpenAsync().Wait());
+ AssertThrowsInAsyncMethod<InvalidOperationException>(
+ Strings.EntityClient_CannotReopenConnection,
+ () => entityConnection.OpenAsync().Wait());
dbConnectionMock.Verify(m => m.Close(), Times.Never());
@@ -665,7 +665,7 @@ public void Underlying_dbConnection_is_not_being_closed_if_it_was_initially_open
}
[Fact]
- public void EntityConnection_with_closed_underlying_connection_maintains_closed_if_metadata_initialization_fails()
+ public void EntityConnection_with_closed_underlying_connection_maintains_closed_if_store_connection_does_not_open_correctly()
{
var dbConnectionMock = new Mock<DbConnection>(MockBehavior.Strict);
dbConnectionMock.Setup(m => m.OpenAsync(It.IsAny<CancellationToken>())).Returns(
@@ -674,11 +674,12 @@ public void EntityConnection_with_closed_underlying_connection_maintains_closed_
dbConnectionMock.SetupGet(m => m.State).Returns(ConnectionState.Closed);
dbConnectionMock.SetupGet(m => m.DataSource).Returns("fake");
- var metadataWorkspaceMock = new Mock<MetadataWorkspace>(MockBehavior.Strict);
- metadataWorkspaceMock.Setup(m => m.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)).Throws<InvalidOperationException>();
- var entityConnection = new EntityConnection(metadataWorkspaceMock.Object, dbConnectionMock.Object, true, true);
+ var entityConnection = new EntityConnection(
+ new Mock<MetadataWorkspace>(MockBehavior.Strict).Object, dbConnectionMock.Object, true, true);
- AssertThrowsInAsyncMethod<InvalidOperationException>(null, () => entityConnection.OpenAsync().Wait());
+ AssertThrowsInAsyncMethod<InvalidOperationException>(
+ Strings.EntityClient_ConnectionNotOpen,
+ () => entityConnection.OpenAsync().Wait());
Assert.Equal(ConnectionState.Closed, entityConnection.State);
}
@@ -997,8 +998,8 @@ public void ExecutionStrategy_is_used_to_recover_from_a_transient_error()
storeConnectionMock.Setup(m => m.Open()).Callback(() => storeConnectionState = ConnectionState.Open);
storeConnectionMock.SetupGet(m => m.DataSource).Returns("fake");
storeConnectionMock.SetupGet(m => m.State).Returns(() => storeConnectionState);
- storeConnectionMock.Protected().Setup<DbTransaction>("BeginDbTransaction", Data.IsolationLevel.Unspecified)
- .Returns<Data.IsolationLevel>(
+ storeConnectionMock.Protected().Setup<DbTransaction>("BeginDbTransaction", IsolationLevel.Unspecified)
+ .Returns<IsolationLevel>(
il =>
{
if (!transientExceptionThrown)
@@ -1021,19 +1022,19 @@ public void ExecutionStrategy_is_used_to_recover_from_a_transient_error()
{
storeConnectionMock.Protected()
.Verify<DbTransaction>(
- "BeginDbTransaction", Times.Never(), Data.IsolationLevel.Unspecified);
+ "BeginDbTransaction", Times.Never(), IsolationLevel.Unspecified);
Assert.Throws<TimeoutException>(() => a());
storeConnectionMock.Protected()
.Verify<DbTransaction>(
- "BeginDbTransaction", Times.Once(), Data.IsolationLevel.Unspecified);
+ "BeginDbTransaction", Times.Once(), IsolationLevel.Unspecified);
var result = a();
storeConnectionMock.Protected()
.Verify<DbTransaction>(
- "BeginDbTransaction", Times.Exactly(2), Data.IsolationLevel.Unspecified);
+ "BeginDbTransaction", Times.Exactly(2), IsolationLevel.Unspecified);
return result;
});
View
27 test/EntityFramework/UnitTests/Core/Mapping/StorageMappingItemCollectionTests.cs
@@ -155,5 +155,32 @@ public void StorageMappingItemCollection_Create_factory_method_returns_StorageMa
Assert.NotNull(storageMappingItemCollection.GetItem<GlobalItem>("AdventureWorksEntities3"));
Assert.Equal(0, errors.Count);
}
+
+ [Fact]
+ public void Workspace_returns_a_new_workspace_with_all_collections_registered()