From 6f65070a7ef19bf11c3d26e7a1ba09ca9aa624db Mon Sep 17 00:00:00 2001 From: Ray Yao Date: Tue, 18 Nov 2014 07:12:00 -0800 Subject: [PATCH] Thread safety and multiple namespace support. In Domain.Core 2 places have been identified as shared states of multiple requests (hence threads), which needs thread safety. In Domain.EntityFramework there's a limitation that entity types must come from a same namespace, it seems that limitation is unnecessary, since OData EDM could gracefully handle schema elements in multiple namespaces. For entity container's namespace, in this fix the most popular one (which has most entity types) is chosen, if there's no entity type, namespace of the DbContext type is chosen, if DbContext type has no namespace, name of the DbContext type is chosen. --- .../Model/ModelProducer.cs | 14 ++++++++-- .../DomainConfiguration.cs | 3 +- .../Model/DomainModel.cs | 28 ++++++------------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/Microsoft.Data.Domain.EntityFramework/Model/ModelProducer.cs b/src/Microsoft.Data.Domain.EntityFramework/Model/ModelProducer.cs index 13deab0c..2311e4c0 100644 --- a/src/Microsoft.Data.Domain.EntityFramework/Model/ModelProducer.cs +++ b/src/Microsoft.Data.Domain.EntityFramework/Model/ModelProducer.cs @@ -71,11 +71,19 @@ public class ModelProducer : IModelProducer .ObjectContext.MetadataWorkspace; var namespaceName = efModel.GetItems(DataSpace.CSpace) .Select(t => efModel.GetObjectSpaceType(t).NamespaceName) - .Distinct().SingleOrDefault(); + .GroupBy(nameSpace => nameSpace) + .Select(group => new + { + NameSpace = group.Key, + Count = group.Count(), + }) + .OrderByDescending(nsItem => nsItem.Count) + .Select(nsItem => nsItem.NameSpace) + .FirstOrDefault(); if (namespaceName == null) { - // TODO: support multiple schemas - throw new NotSupportedException(); + // When dbContext has not a namespace, just use its type name as namespace. + namespaceName = dbContext.GetType().Namespace ?? dbContext.GetType().Name; } var efEntityContainer = efModel.GetItems< diff --git a/src/Microsoft.Data.Domain/DomainConfiguration.cs b/src/Microsoft.Data.Domain/DomainConfiguration.cs index 0165881d..7a338e3d 100644 --- a/src/Microsoft.Data.Domain/DomainConfiguration.cs +++ b/src/Microsoft.Data.Domain/DomainConfiguration.cs @@ -20,6 +20,7 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -76,7 +77,7 @@ public class DomainConfiguration : PropertyBag { private static readonly DomainConfiguration s_global = new DomainConfiguration(); private static readonly IDictionary s_configurations = - new Dictionary(); + new ConcurrentDictionary(); private readonly IDictionary _singletons = new Dictionary(); diff --git a/src/Microsoft.Data.Domain/Model/DomainModel.cs b/src/Microsoft.Data.Domain/Model/DomainModel.cs index cecd9484..f5ad6407 100644 --- a/src/Microsoft.Data.Domain/Model/DomainModel.cs +++ b/src/Microsoft.Data.Domain/Model/DomainModel.cs @@ -18,10 +18,13 @@ // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -using System.Collections.Generic; -using System.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Annotations; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; namespace Microsoft.Data.Domain.Model { @@ -30,7 +33,8 @@ namespace Microsoft.Data.Domain.Model // to elements that are not supposed to be visible. internal class DomainModel : IEdmModel { - private IDictionary _entityContainers; + private readonly Lazy> _entityContainers = + new Lazy>(LazyThreadSafetyMode.PublicationOnly); public DomainModel(DomainConfiguration configuration, IEdmModel model) { @@ -204,22 +208,8 @@ private bool IsVocabularyAnnotatableVisible( private DomainEntityContainer GetDomainEntityContainer( IEdmEntityContainer entityContainer) { - if (this._entityContainers == null) - { - this._entityContainers = new Dictionary< - string, DomainEntityContainer>(); - } - DomainEntityContainer domainEntityContainer = null; - if (!this._entityContainers.TryGetValue( - entityContainer.FullName(), - out domainEntityContainer)) - { - domainEntityContainer = new DomainEntityContainer( - this, entityContainer); - this._entityContainers.Add( - entityContainer.FullName(), - domainEntityContainer); - } + var domainEntityContainer = this._entityContainers.Value.GetOrAdd( + entityContainer.FullName(), name => new DomainEntityContainer(this, entityContainer)); return domainEntityContainer; } }