From: <fab...@us...> - 2011-05-08 22:59:25
|
Revision: 5800 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5800&view=rev Author: fabiomaulo Date: 2011-05-08 22:59:17 +0000 (Sun, 08 May 2011) Log Message: ----------- Fixed class registration ambiguity resolution Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/ComponentMappingRegistrationTests.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/JoinedSubclassMappingStrategyTests.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/RootClassMappingStrategyTests.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/SubclassMappingStrategyTests.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/UnionSubclassMappingStrategyTests.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/AbstractExplicitlyDeclaredModel.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/MixAutomapping/CallCustomConditions.cs Added: trunk/nhibernate/src/NHibernate/Mapping/ByCode/AbstractExplicitlyDeclaredModel.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/AbstractExplicitlyDeclaredModel.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/AbstractExplicitlyDeclaredModel.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -0,0 +1,571 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace NHibernate.Mapping.ByCode +{ + public abstract class AbstractExplicitlyDeclaredModel : IModelExplicitDeclarationsHolder + { + private readonly HashSet<MemberInfo> any = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> arrays = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> bags = new HashSet<MemberInfo>(); + private readonly HashSet<System.Type> components = new HashSet<System.Type>(); + private readonly HashSet<MemberInfo> dictionaries = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> idBags = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> lists = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> manyToManyRelations = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> manyToOneRelations = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> naturalIds = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> composedIds = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> oneToManyRelations = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> oneToOneRelations = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> poids = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> properties = new HashSet<MemberInfo>(); + private readonly HashSet<MemberInfo> dynamicComponents = new HashSet<MemberInfo>(); + private readonly Dictionary<MemberInfo, System.Type> dynamicComponentTemplates = new Dictionary<MemberInfo, System.Type>(); + private readonly HashSet<MemberInfo> persistentMembers = new HashSet<MemberInfo>(); + private readonly HashSet<System.Type> rootEntities = new HashSet<System.Type>(); + private readonly HashSet<MemberInfo> sets = new HashSet<MemberInfo>(); + private readonly HashSet<System.Type> tablePerClassEntities = new HashSet<System.Type>(); + private readonly HashSet<System.Type> tablePerClassHierarchyEntities = new HashSet<System.Type>(); + private readonly HashSet<System.Type> tablePerConcreteClassEntities = new HashSet<System.Type>(); + private readonly HashSet<MemberInfo> versionProperties = new HashSet<MemberInfo>(); + private readonly Dictionary<System.Type, HashSet<string>> typeSplitGroups = new Dictionary<System.Type, HashSet<string>>(); + private readonly Dictionary<MemberInfo, string> memberSplitGroup = new Dictionary<MemberInfo, string>(); + private readonly HashSet<SplitDefinition> splitDefinitions = new HashSet<SplitDefinition>(); + + #region Delayed registrations + // To allow a free organization of mappings, especially in presence of a IModelMapper not based exclusivelly on pure declarative mapping, and then + // provide a descriptive exception when there are some ambiguity, we have to delay the registration as late as we can + // (in practice to the moment we have to give a certain asnwer about the strategy used to represent a System.Type hierarchy). + private readonly Queue<System.Action> delayedRootEntityRegistrations = new Queue<System.Action>(); + private readonly Dictionary<System.Type, List<Action<System.Type>>> delayedEntityRegistrations = new Dictionary<System.Type, List<Action<System.Type>>>(); + + #endregion + + public IEnumerable<System.Type> RootEntities + { + get { return rootEntities; } + } + + public IEnumerable<System.Type> Components + { + get { return components; } + } + + public IEnumerable<System.Type> TablePerClassEntities + { + get { return tablePerClassEntities; } + } + + public IEnumerable<System.Type> TablePerClassHierarchyEntities + { + get { return tablePerClassHierarchyEntities; } + } + + public IEnumerable<System.Type> TablePerConcreteClassEntities + { + get { return tablePerConcreteClassEntities; } + } + + public IEnumerable<MemberInfo> OneToOneRelations + { + get { return oneToOneRelations; } + } + + public IEnumerable<MemberInfo> ManyToOneRelations + { + get { return manyToOneRelations; } + } + + public IEnumerable<MemberInfo> ManyToManyRelations + { + get { return manyToManyRelations; } + } + + public IEnumerable<MemberInfo> OneToManyRelations + { + get { return oneToManyRelations; } + } + + public IEnumerable<MemberInfo> Any + { + get { return any; } + } + + public IEnumerable<MemberInfo> Poids + { + get { return poids; } + } + + public IEnumerable<MemberInfo> ComposedIds + { + get { return composedIds; } + } + + public IEnumerable<MemberInfo> VersionProperties + { + get { return versionProperties; } + } + + public IEnumerable<MemberInfo> NaturalIds + { + get { return naturalIds; } + } + + public IEnumerable<MemberInfo> Sets + { + get { return sets; } + } + + public IEnumerable<MemberInfo> Bags + { + get { return bags; } + } + + public IEnumerable<MemberInfo> IdBags + { + get { return idBags; } + } + + public IEnumerable<MemberInfo> Lists + { + get { return lists; } + } + + public IEnumerable<MemberInfo> Arrays + { + get { return arrays; } + } + + public IEnumerable<MemberInfo> Dictionaries + { + get { return dictionaries; } + } + + public IEnumerable<MemberInfo> Properties + { + get { return properties; } + } + + public IEnumerable<MemberInfo> DynamicComponents + { + get { return dynamicComponents; } + } + + public IEnumerable<MemberInfo> PersistentMembers + { + get { return persistentMembers; } + } + + public IEnumerable<SplitDefinition> SplitDefinitions + { + get { return splitDefinitions; } + } + + public IEnumerable<string> GetSplitGroupsFor(System.Type type) + { + HashSet<string> splitsGroupsIds; + if (typeSplitGroups.TryGetValue(type, out splitsGroupsIds)) + { + return splitsGroupsIds; + } + return Enumerable.Empty<string>(); + } + + public string GetSplitGroupFor(MemberInfo member) + { + var memberKey = member.GetMemberFromDeclaringType(); + string splitGroup; + if (memberSplitGroup.TryGetValue(memberKey, out splitGroup)) + { + return splitGroup; + } + return null; + } + + public void AddAsRootEntity(System.Type type) + { + rootEntities.Add(type); + if (IsComponent(type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); + } + } + + public abstract bool IsComponent(System.Type type); + + public void AddAsComponent(System.Type type) + { + components.Add(type); + var rootEntity = GetSingleRootEntityOrNull(type); + if (rootEntity != null) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); + } + } + + public void AddAsTablePerClassEntity(System.Type type) + { + AddAsTablePerClassEntity(type, false); + } + + protected virtual void AddAsTablePerClassEntity(System.Type type, bool rootEntityMustExists) + { + if(!rootEntityMustExists) + { + delayedRootEntityRegistrations.Enqueue(() => System.Array.ForEach(GetRootEntitentitiesOf(type).ToArray(), root=> tablePerClassEntities.Add(root))); + EnlistTypeRegistration(type, t => AddAsTablePerClassEntity(t, true)); + return; + } + if (IsComponent(type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); + } + var rootEntity = GetSingleRootEntityOrNull(type); + if (rootEntity != null) + { + if (rootEntity.Equals(type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as root-entity and as subclass for table-per-class strategy", type.FullName)); + } + if (IsMappedFor(tablePerClassHierarchyEntities, type) || IsMappedFor(tablePerConcreteClassEntities, type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered with more than one class-hierarchy strategy", type.FullName)); + } + } + else + { + throw new MappingException(string.Format("The root entity for {0} was never registered", type.FullName)); + } + } + + public void AddAsTablePerClassHierarchyEntity(System.Type type) + { + AddAsTablePerClassHierarchyEntity(type, false); + } + + protected virtual void AddAsTablePerClassHierarchyEntity(System.Type type, bool rootEntityMustExists) + { + if (!rootEntityMustExists) + { + delayedRootEntityRegistrations.Enqueue(() => System.Array.ForEach(GetRootEntitentitiesOf(type).ToArray(), root => tablePerClassHierarchyEntities.Add(root))); + EnlistTypeRegistration(type, t => AddAsTablePerClassHierarchyEntity(t, true)); + return; + } + + if (IsComponent(type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); + } + var rootEntity = GetSingleRootEntityOrNull(type); + if (rootEntity != null) + { + if (rootEntity.Equals(type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as root-entity and as subclass for table-per-class-hierarchy strategy", type.FullName)); + } + if (IsMappedFor(tablePerClassEntities, type) || IsMappedFor(tablePerConcreteClassEntities, type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered with more than one class-hierarchy strategy", type.FullName)); + } + } + else + { + throw new MappingException(string.Format("The root entity for {0} was never registered", type.FullName)); + } + } + + public void AddAsTablePerConcreteClassEntity(System.Type type) + { + AddAsTablePerConcreteClassEntity(type, false); + } + + protected virtual void AddAsTablePerConcreteClassEntity(System.Type type, bool rootEntityMustExists) + { + if (!rootEntityMustExists) + { + delayedRootEntityRegistrations.Enqueue(() => System.Array.ForEach(GetRootEntitentitiesOf(type).ToArray(), root => tablePerConcreteClassEntities.Add(root))); + EnlistTypeRegistration(type, t => AddAsTablePerConcreteClassEntity(t, true)); + return; + } + + if (IsComponent(type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); + } + var rootEntity = GetSingleRootEntityOrNull(type); + if (rootEntity != null) + { + if (rootEntity.Equals(type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as root-entity and as subclass for table-per-concrete-class strategy", type.FullName)); + } + if (IsMappedFor(tablePerClassEntities, type) || IsMappedFor(tablePerClassHierarchyEntities, type)) + { + throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered with more than one class-hierarchy strategy", type.FullName)); + } + } + else + { + throw new MappingException(string.Format("The root entity for {0} was never registered", type.FullName)); + } + } + + public void AddAsOneToOneRelation(MemberInfo member) + { + persistentMembers.Add(member); + oneToOneRelations.Add(member); + } + + public void AddAsManyToOneRelation(MemberInfo member) + { + persistentMembers.Add(member); + manyToOneRelations.Add(member); + } + + public void AddAsManyToManyRelation(MemberInfo member) + { + persistentMembers.Add(member); + manyToManyRelations.Add(member); + } + + public void AddAsOneToManyRelation(MemberInfo member) + { + persistentMembers.Add(member); + oneToManyRelations.Add(member); + } + + public void AddAsAny(MemberInfo member) + { + persistentMembers.Add(member); + any.Add(member); + } + + public void AddAsPoid(MemberInfo member) + { + persistentMembers.Add(member); + poids.Add(member); + } + + public void AddAsPartOfComposedId(MemberInfo member) + { + persistentMembers.Add(member); + composedIds.Add(member); + } + + public void AddAsVersionProperty(MemberInfo member) + { + persistentMembers.Add(member); + versionProperties.Add(member); + } + + public void AddAsNaturalId(MemberInfo member) + { + persistentMembers.Add(member); + naturalIds.Add(member); + } + + public void AddAsSet(MemberInfo member) + { + persistentMembers.Add(member); + sets.Add(member); + } + + public void AddAsBag(MemberInfo member) + { + persistentMembers.Add(member); + bags.Add(member); + } + + public void AddAsIdBag(MemberInfo member) + { + persistentMembers.Add(member); + idBags.Add(member); + } + + public void AddAsList(MemberInfo member) + { + persistentMembers.Add(member); + lists.Add(member); + } + + public void AddAsArray(MemberInfo member) + { + persistentMembers.Add(member); + arrays.Add(member); + } + + public void AddAsMap(MemberInfo member) + { + persistentMembers.Add(member); + dictionaries.Add(member); + } + + public void AddAsProperty(MemberInfo member) + { + persistentMembers.Add(member); + properties.Add(member); + } + + public void AddAsPersistentMember(MemberInfo member) + { + persistentMembers.Add(member); + } + + public void AddAsPropertySplit(SplitDefinition definition) + { + if (definition == null) + { + return; + } + /* Note: if the user "jump/exclude" a class and then map the property in two subclasses the usage of GetMemberFromDeclaringType() may cause a problem + for a legal usage... we will see when the case happen */ + System.Type propertyContainer = definition.On; + string splitGroupId = definition.GroupId; + MemberInfo member = definition.Member; + var memberKey = member.GetMemberFromDeclaringType(); + string splitGroup; + if (!memberSplitGroup.TryGetValue(memberKey, out splitGroup)) + { + AddTypeSplits(propertyContainer, splitGroupId); + memberSplitGroup[memberKey] = splitGroupId; + } + + splitDefinitions.Add(definition); + } + + public void AddAsDynamicComponent(MemberInfo member, System.Type componentTemplate) + { + persistentMembers.Add(member); + dynamicComponents.Add(member); + dynamicComponentTemplates[member] = componentTemplate; + } + + private void AddTypeSplits(System.Type propertyContainer, string splitGroupId) + { + HashSet<string> splitsGroupsIds; + typeSplitGroups.TryGetValue(propertyContainer, out splitsGroupsIds); + if(splitsGroupsIds == null) + { + splitsGroupsIds = new HashSet<string>(); + typeSplitGroups[propertyContainer] = splitsGroupsIds; + } + splitsGroupsIds.Add(splitGroupId); + } + + public virtual System.Type GetDynamicComponentTemplate(MemberInfo member) + { + System.Type template; + dynamicComponentTemplates.TryGetValue(member, out template); + return template ?? typeof(object); + } + + protected System.Type GetSingleRootEntityOrNull(System.Type entityType) + { + var rootTypes = GetRootEntitentitiesOf(entityType).ToList(); + if(rootTypes.Count > 1) + { + var sb = new StringBuilder(1024); + sb.AppendLine(string.Format("Ambiguous mapping for {0}. More than one root entities was found:", entityType.FullName)); + foreach (var rootType in rootTypes.AsEnumerable().Reverse()) + { + sb.AppendLine(rootType.FullName); + } + sb.AppendLine("Possible solutions:"); + sb.AppendLine("- Merge the mappings of root entity in the one is representing the real root of the hierarchy."); + sb.AppendLine("- Inject a IModelInspector with a logic to discover the real root-entity."); + throw new MappingException(sb.ToString()); + } + return rootTypes.SingleOrDefault(IsRootEntity); + } + + protected IEnumerable<System.Type> GetRootEntitentitiesOf(System.Type entityType) + { + if (entityType == null) + { + yield break; + } + if(IsRootEntity(entityType)) + { + yield return entityType; + } + foreach (var type in entityType.GetBaseTypes().Where(IsRootEntity)) + { + yield return type; + } + } + + public abstract bool IsRootEntity(System.Type entityType); + + protected bool IsMappedForTablePerClassEntities(System.Type type) + { + return IsMappedFor(tablePerClassEntities, type); + } + + protected bool IsMappedForTablePerClassHierarchyEntities(System.Type type) + { + return IsMappedFor(tablePerClassHierarchyEntities, type); + } + + protected bool IsMappedForTablePerConcreteClassEntities(System.Type type) + { + return IsMappedFor(tablePerConcreteClassEntities, type); + } + + private bool IsMappedFor(ICollection<System.Type> explicitMappedEntities, System.Type type) + { + bool isExplicitMapped = explicitMappedEntities.Contains(type); + bool isDerived = false; + + if (!isExplicitMapped) + { + isDerived = type.GetBaseTypes().Any(explicitMappedEntities.Contains); + if (isDerived) + { + explicitMappedEntities.Add(type); + } + } + return isExplicitMapped || isDerived; + } + + protected void EnlistTypeRegistration(System.Type type, Action<System.Type> registration) + { + List<Action<System.Type>> actions; + if (!delayedEntityRegistrations.TryGetValue(type, out actions)) + { + actions = new List<Action<System.Type>>(); + delayedEntityRegistrations[type] = actions; + } + actions.Add(registration); + } + + protected void ExecuteDelayedTypeRegistration(System.Type type) + { + ExecuteDelayedRootEntitiesRegistrations(); + List<Action<System.Type>> actions; + if (delayedEntityRegistrations.TryGetValue(type, out actions)) + { + foreach (var action in actions) + { + action(type); + } + } + } + + protected void ExecuteDelayedRootEntitiesRegistrations() + { + while (delayedRootEntityRegistrations.Count > 0) + { + delayedRootEntityRegistrations.Dequeue().Invoke(); + } + } + + protected bool HasDelayedEntityRegistration(System.Type type) + { + return delayedEntityRegistrations.ContainsKey(type); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ExplicitlyDeclaredModel.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -1,470 +1,32 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace NHibernate.Mapping.ByCode { - public class ExplicitlyDeclaredModel : IModelInspector, IModelExplicitDeclarationsHolder + public class ExplicitlyDeclaredModel : AbstractExplicitlyDeclaredModel, IModelInspector { - private readonly HashSet<MemberInfo> any = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> arrays = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> bags = new HashSet<MemberInfo>(); - private readonly HashSet<System.Type> components = new HashSet<System.Type>(); - private readonly HashSet<MemberInfo> dictionaries = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> idBags = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> lists = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> manyToManyRelations = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> manyToOneRelations = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> naturalIds = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> composedIds = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> oneToManyRelations = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> oneToOneRelations = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> poids = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> properties = new HashSet<MemberInfo>(); - private readonly HashSet<MemberInfo> dynamicComponents = new HashSet<MemberInfo>(); - private readonly Dictionary<MemberInfo, System.Type> dynamicComponentTemplates = new Dictionary<MemberInfo, System.Type>(); - private readonly HashSet<MemberInfo> persistentMembers = new HashSet<MemberInfo>(); - private readonly HashSet<System.Type> rootEntities = new HashSet<System.Type>(); - private readonly HashSet<MemberInfo> sets = new HashSet<MemberInfo>(); - private readonly HashSet<System.Type> tablePerClassEntities = new HashSet<System.Type>(); - private readonly HashSet<System.Type> tablePerClassHierarchyEntities = new HashSet<System.Type>(); - private readonly HashSet<System.Type> tablePerConcreteClassEntities = new HashSet<System.Type>(); - private readonly HashSet<MemberInfo> versionProperties = new HashSet<MemberInfo>(); - private readonly Dictionary<System.Type, Action<System.Type>> delayedEntityRegistrations = new Dictionary<System.Type, Action<System.Type>>(); - private readonly Dictionary<System.Type, HashSet<string>> typeSplitGroups = new Dictionary<System.Type, HashSet<string>>(); - private readonly Dictionary<MemberInfo, string> memberSplitGroup = new Dictionary<MemberInfo, string>(); - private readonly HashSet<SplitDefinition> splitDefinitions = new HashSet<SplitDefinition>(); - - #region IModelExplicitDeclarationsHolder Members - - public IEnumerable<System.Type> RootEntities - { - get { return rootEntities; } - } - - public IEnumerable<System.Type> Components - { - get { return components; } - } - - public IEnumerable<System.Type> TablePerClassEntities - { - get { return tablePerClassEntities; } - } - - public IEnumerable<System.Type> TablePerClassHierarchyEntities - { - get { return tablePerClassHierarchyEntities; } - } - - public IEnumerable<System.Type> TablePerConcreteClassEntities - { - get { return tablePerConcreteClassEntities; } - } - - public IEnumerable<MemberInfo> OneToOneRelations - { - get { return oneToOneRelations; } - } - - public IEnumerable<MemberInfo> ManyToOneRelations - { - get { return manyToOneRelations; } - } - - public IEnumerable<MemberInfo> ManyToManyRelations - { - get { return manyToManyRelations; } - } - - public IEnumerable<MemberInfo> OneToManyRelations - { - get { return oneToManyRelations; } - } - - public IEnumerable<MemberInfo> Any - { - get { return any; } - } - - public IEnumerable<MemberInfo> Poids - { - get { return poids; } - } - - public IEnumerable<MemberInfo> ComposedIds - { - get { return composedIds; } - } - - public IEnumerable<MemberInfo> VersionProperties - { - get { return versionProperties; } - } - - public IEnumerable<MemberInfo> NaturalIds - { - get { return naturalIds; } - } - - public IEnumerable<MemberInfo> Sets - { - get { return sets; } - } - - public IEnumerable<MemberInfo> Bags - { - get { return bags; } - } - - public IEnumerable<MemberInfo> IdBags - { - get { return idBags; } - } - - public IEnumerable<MemberInfo> Lists - { - get { return lists; } - } - - public IEnumerable<MemberInfo> Arrays - { - get { return arrays; } - } - - public IEnumerable<MemberInfo> Dictionaries - { - get { return dictionaries; } - } - - public IEnumerable<MemberInfo> Properties - { - get { return properties; } - } - - public IEnumerable<MemberInfo> DynamicComponents - { - get { return dynamicComponents; } - } - - public IEnumerable<MemberInfo> PersistentMembers - { - get { return persistentMembers; } - } - - public IEnumerable<SplitDefinition> SplitDefinitions - { - get { return splitDefinitions; } - } - - public IEnumerable<string> GetSplitGroupsFor(System.Type type) - { - HashSet<string> splitsGroupsIds; - if (typeSplitGroups.TryGetValue(type, out splitsGroupsIds)) - { - return splitsGroupsIds; - } - return Enumerable.Empty<string>(); - } - - public string GetSplitGroupFor(MemberInfo member) - { - var memberKey = member.GetMemberFromDeclaringType(); - string splitGroup; - if (memberSplitGroup.TryGetValue(memberKey, out splitGroup)) - { - return splitGroup; - } - return null; - } - - public void AddAsRootEntity(System.Type type) - { - if (IsComponent(type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); - } - rootEntities.Add(type); - } - - public void AddAsComponent(System.Type type) - { - var rootEntity = GetRootEntityOrNull(type); - if (rootEntity != null) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); - } - components.Add(type); - } - - public void AddAsTablePerClassEntity(System.Type type) - { - AddAsTablePerClassEntity(type, false); - } - - public void AddAsTablePerClassEntity(System.Type type, bool rootEntityMustExists) - { - if (IsComponent(type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); - } - var rootEntity = GetRootEntityOrNull(type); - if (rootEntity != null) - { - if (rootEntity.Equals(type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as root-entity and as subclass for table-per-class strategy", type.FullName)); - } - if (IsMappedFor(tablePerClassHierarchyEntities, type) || IsMappedFor(tablePerConcreteClassEntities, type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered with more than one class-hierarchy strategy", type.FullName)); - } - tablePerClassEntities.Add(rootEntity); - } - else - { - if(rootEntityMustExists) - { - throw new MappingException(string.Format("The root entity for {0} was never registered", type.FullName)); - } - EnlistTypeRegistration(type, t => AddAsTablePerClassEntity(t, true)); - } - } - - public void AddAsTablePerClassHierarchyEntity(System.Type type) - { - AddAsTablePerClassHierarchyEntity(type, false); - } - - public void AddAsTablePerClassHierarchyEntity(System.Type type, bool rootEntityMustExists) - { - if (IsComponent(type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); - } - var rootEntity = GetRootEntityOrNull(type); - if (rootEntity != null) - { - if (rootEntity.Equals(type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as root-entity and as subclass for table-per-class-hierarchy strategy", type.FullName)); - } - if (IsMappedFor(tablePerClassEntities, type) || IsMappedFor(tablePerConcreteClassEntities, type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered with more than one class-hierarchy strategy", type.FullName)); - } - tablePerClassHierarchyEntities.Add(rootEntity); - } - else - { - if (rootEntityMustExists) - { - throw new MappingException(string.Format("The root entity for {0} was never registered", type.FullName)); - } - EnlistTypeRegistration(type, t => AddAsTablePerClassHierarchyEntity(t, true)); - } - } - - public void AddAsTablePerConcreteClassEntity(System.Type type) - { - AddAsTablePerConcreteClassEntity(type, false); - } - - public void AddAsTablePerConcreteClassEntity(System.Type type, bool rootEntityMustExists) - { - if (IsComponent(type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as entity and as component", type.FullName)); - } - var rootEntity = GetRootEntityOrNull(type); - if (rootEntity != null) - { - if (rootEntity.Equals(type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered as root-entity and as subclass for table-per-concrete-class strategy", type.FullName)); - } - if (IsMappedFor(tablePerClassEntities, type) || IsMappedFor(tablePerClassHierarchyEntities, type)) - { - throw new MappingException(string.Format("Ambiguous mapping of {0}. It was registered with more than one class-hierarchy strategy", type.FullName)); - } - tablePerConcreteClassEntities.Add(rootEntity); - } - else - { - if (rootEntityMustExists) - { - throw new MappingException(string.Format("The root entity for {0} was never registered", type.FullName)); - } - EnlistTypeRegistration(type, t => AddAsTablePerConcreteClassEntity(t, true)); - } - } - - public void AddAsOneToOneRelation(MemberInfo member) - { - persistentMembers.Add(member); - oneToOneRelations.Add(member); - } - - public void AddAsManyToOneRelation(MemberInfo member) - { - persistentMembers.Add(member); - manyToOneRelations.Add(member); - } - - public void AddAsManyToManyRelation(MemberInfo member) - { - persistentMembers.Add(member); - manyToManyRelations.Add(member); - } - - public void AddAsOneToManyRelation(MemberInfo member) - { - persistentMembers.Add(member); - oneToManyRelations.Add(member); - } - - public void AddAsAny(MemberInfo member) - { - persistentMembers.Add(member); - any.Add(member); - } - - public void AddAsPoid(MemberInfo member) - { - persistentMembers.Add(member); - poids.Add(member); - } - - public void AddAsPartOfComposedId(MemberInfo member) - { - persistentMembers.Add(member); - composedIds.Add(member); - } - - public void AddAsVersionProperty(MemberInfo member) - { - persistentMembers.Add(member); - versionProperties.Add(member); - } - - public void AddAsNaturalId(MemberInfo member) - { - persistentMembers.Add(member); - naturalIds.Add(member); - } - - public void AddAsSet(MemberInfo member) - { - persistentMembers.Add(member); - sets.Add(member); - } - - public void AddAsBag(MemberInfo member) - { - persistentMembers.Add(member); - bags.Add(member); - } - - public void AddAsIdBag(MemberInfo member) - { - persistentMembers.Add(member); - idBags.Add(member); - } - - public void AddAsList(MemberInfo member) - { - persistentMembers.Add(member); - lists.Add(member); - } - - public void AddAsArray(MemberInfo member) - { - persistentMembers.Add(member); - arrays.Add(member); - } - - public void AddAsMap(MemberInfo member) - { - persistentMembers.Add(member); - dictionaries.Add(member); - } - - public void AddAsProperty(MemberInfo member) - { - persistentMembers.Add(member); - properties.Add(member); - } - - public void AddAsPersistentMember(MemberInfo member) - { - persistentMembers.Add(member); - } - - public void AddAsPropertySplit(SplitDefinition definition) - { - if (definition == null) - { - return; - } - /* Note: if the user "jump/exclude" a class and then map the property in two subclasses the usage of GetMemberFromDeclaringType() may cause a problem - for a legal usage... we will see when the case happen */ - System.Type propertyContainer = definition.On; - string splitGroupId = definition.GroupId; - MemberInfo member = definition.Member; - var memberKey = member.GetMemberFromDeclaringType(); - string splitGroup; - if (!memberSplitGroup.TryGetValue(memberKey, out splitGroup)) - { - AddTypeSplits(propertyContainer, splitGroupId); - memberSplitGroup[memberKey] = splitGroupId; - } - - splitDefinitions.Add(definition); - } - - public void AddAsDynamicComponent(MemberInfo member, System.Type componentTemplate) - { - persistentMembers.Add(member); - dynamicComponents.Add(member); - dynamicComponentTemplates[member] = componentTemplate; - } - - private void AddTypeSplits(System.Type propertyContainer, string splitGroupId) - { - HashSet<string> splitsGroupsIds; - typeSplitGroups.TryGetValue(propertyContainer, out splitsGroupsIds); - if(splitsGroupsIds == null) - { - splitsGroupsIds = new HashSet<string>(); - typeSplitGroups[propertyContainer] = splitsGroupsIds; - } - splitsGroupsIds.Add(splitGroupId); - } - - #endregion - #region Implementation of IModelInspector - public virtual bool IsRootEntity(System.Type type) + public override bool IsRootEntity(System.Type type) { - return rootEntities.Contains(type); + return RootEntities.Contains(type); } - public virtual bool IsComponent(System.Type type) + public override bool IsComponent(System.Type type) { - return components.Contains(type); + return Components.Contains(type); } public virtual bool IsEntity(System.Type type) { - return rootEntities.Contains(type) || type.GetBaseTypes().Any(t => rootEntities.Contains(t)) || HasDelayedEntityRegistration(type); + return RootEntities.Contains(type) || type.GetBaseTypes().Any(t => RootEntities.Contains(t)) || HasDelayedEntityRegistration(type); } public virtual bool IsTablePerClass(System.Type type) { ExecuteDelayedTypeRegistration(type); - return IsMappedFor(tablePerClassEntities, type); + return IsMappedForTablePerClassEntities(type); } public virtual bool IsTablePerClassSplit(System.Type type, object splitGroupId, MemberInfo member) @@ -475,166 +37,110 @@ public virtual bool IsTablePerClassHierarchy(System.Type type) { ExecuteDelayedTypeRegistration(type); - return IsMappedFor(tablePerClassHierarchyEntities, type); + return IsMappedForTablePerClassHierarchyEntities(type); } public virtual bool IsTablePerConcreteClass(System.Type type) { ExecuteDelayedTypeRegistration(type); - return IsMappedFor(tablePerConcreteClassEntities, type); + return IsMappedForTablePerConcreteClassEntities(type); } public virtual bool IsOneToOne(MemberInfo member) { - return oneToOneRelations.Contains(member); + return OneToOneRelations.Contains(member); } public virtual bool IsManyToOne(MemberInfo member) { - return manyToOneRelations.Contains(member); + return ManyToOneRelations.Contains(member); } public virtual bool IsManyToMany(MemberInfo member) { - return manyToManyRelations.Contains(member); + return ManyToManyRelations.Contains(member); } public virtual bool IsOneToMany(MemberInfo member) { - return oneToManyRelations.Contains(member); + return OneToManyRelations.Contains(member); } public virtual bool IsAny(MemberInfo member) { - return any.Contains(member); + return Any.Contains(member); } public virtual bool IsPersistentId(MemberInfo member) { - return poids.Contains(member); + return Poids.Contains(member); } public bool IsMemberOfComposedId(MemberInfo member) { - return composedIds.Contains(member); + return ComposedIds.Contains(member); } public virtual bool IsVersion(MemberInfo member) { - return versionProperties.Contains(member); + return VersionProperties.Contains(member); } public virtual bool IsMemberOfNaturalId(MemberInfo member) { - return naturalIds.Contains(member); + return NaturalIds.Contains(member); } public virtual bool IsPersistentProperty(MemberInfo member) { - return persistentMembers.Contains(member); + return PersistentMembers.Contains(member); } public virtual bool IsSet(MemberInfo role) { - return sets.Contains(role); + return Sets.Contains(role); } public virtual bool IsBag(MemberInfo role) { - return bags.Contains(role); + return Bags.Contains(role); } public virtual bool IsIdBag(MemberInfo role) { - return idBags.Contains(role); + return IdBags.Contains(role); } public virtual bool IsList(MemberInfo role) { - return lists.Contains(role); + return Lists.Contains(role); } public virtual bool IsArray(MemberInfo role) { - return arrays.Contains(role); + return Arrays.Contains(role); } public virtual bool IsDictionary(MemberInfo role) { - return dictionaries.Contains(role); + return Dictionaries.Contains(role); } public virtual bool IsProperty(MemberInfo member) { - return properties.Contains(member); + return Properties.Contains(member); } - public bool IsDynamicComponent(MemberInfo member) + public virtual bool IsDynamicComponent(MemberInfo member) { - return dynamicComponents.Contains(member); + return DynamicComponents.Contains(member); } - public System.Type GetDynamicComponentTemplate(MemberInfo member) + public virtual IEnumerable<string> GetPropertiesSplits(System.Type type) { - System.Type template; - dynamicComponentTemplates.TryGetValue(member, out template); - return template ?? typeof(object); - } - - public IEnumerable<string> GetPropertiesSplits(System.Type type) - { return GetSplitGroupsFor(type); } #endregion - - protected System.Type GetRootEntityOrNull(System.Type entityType) - { - if (entityType == null) - { - return null; - } - if (IsRootEntity(entityType)) - { - return entityType; - } - return entityType.GetBaseTypes().SingleOrDefault(IsRootEntity); - } - - protected bool IsMappedFor(ICollection<System.Type> explicitMappedEntities, System.Type type) - { - bool isExplicitMapped = explicitMappedEntities.Contains(type); - bool isDerived = false; - - if (!isExplicitMapped) - { - isDerived = type.GetBaseTypes().Any(explicitMappedEntities.Contains); - if (isDerived) - { - explicitMappedEntities.Add(type); - } - } - return isExplicitMapped || isDerived; - } - - protected void EnlistTypeRegistration(System.Type type, Action<System.Type> registration) - { - delayedEntityRegistrations.Add(type, registration); - } - - protected void ExecuteDelayedTypeRegistration(System.Type type) - { - Action<System.Type> registration; - if(delayedEntityRegistrations.TryGetValue(type, out registration)) - { - delayedEntityRegistrations.Remove(type); - registration(type); - } - } - - protected bool HasDelayedEntityRegistration(System.Type type) - { - return delayedEntityRegistrations.ContainsKey(type); - } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/SimpleModelInspector.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -11,8 +11,151 @@ /// </summary> public class SimpleModelInspector : IModelInspector, IModelExplicitDeclarationsHolder { - private readonly ExplicitlyDeclaredModel declaredModel = new ExplicitlyDeclaredModel(); + private class MixinDeclaredModel : AbstractExplicitlyDeclaredModel + { + private readonly IModelInspector inspector; + public MixinDeclaredModel(IModelInspector inspector) + { + this.inspector = inspector; + } + + public override bool IsComponent(System.Type type) + { + return Components.Contains(type); + } + + public override bool IsRootEntity(System.Type entityType) + { + return inspector.IsRootEntity(entityType); + } + + public bool IsEntity(System.Type type) + { + return RootEntities.Contains(type) || type.GetBaseTypes().Any(t => RootEntities.Contains(t)) || HasDelayedEntityRegistration(type); + } + + public bool IsTablePerClass(System.Type type) + { + ExecuteDelayedTypeRegistration(type); + return IsMappedForTablePerClassEntities(type); + } + + public bool IsTablePerClassSplit(System.Type type, object splitGroupId, MemberInfo member) + { + return Equals(splitGroupId, GetSplitGroupFor(member)); + } + + public bool IsTablePerClassHierarchy(System.Type type) + { + ExecuteDelayedTypeRegistration(type); + return IsMappedForTablePerClassHierarchyEntities(type); + } + + public bool IsTablePerConcreteClass(System.Type type) + { + ExecuteDelayedTypeRegistration(type); + return IsMappedForTablePerConcreteClassEntities(type); + } + + public bool IsOneToOne(MemberInfo member) + { + return OneToOneRelations.Contains(member); + } + + public bool IsManyToOne(MemberInfo member) + { + return ManyToOneRelations.Contains(member); + } + + public bool IsManyToMany(MemberInfo member) + { + return ManyToManyRelations.Contains(member); + } + + public bool IsOneToMany(MemberInfo member) + { + return OneToManyRelations.Contains(member); + } + + public bool IsAny(MemberInfo member) + { + return Any.Contains(member); + } + + public bool IsPersistentId(MemberInfo member) + { + return Poids.Contains(member); + } + + public bool IsMemberOfComposedId(MemberInfo member) + { + return ComposedIds.Contains(member); + } + + public bool IsVersion(MemberInfo member) + { + return VersionProperties.Contains(member); + } + + public bool IsMemberOfNaturalId(MemberInfo member) + { + return NaturalIds.Contains(member); + } + + public bool IsPersistentProperty(MemberInfo member) + { + return PersistentMembers.Contains(member); + } + + public bool IsSet(MemberInfo role) + { + return Sets.Contains(role); + } + + public bool IsBag(MemberInfo role) + { + return Bags.Contains(role); + } + + public bool IsIdBag(MemberInfo role) + { + return IdBags.Contains(role); + } + + public bool IsList(MemberInfo role) + { + return Lists.Contains(role); + } + + public bool IsArray(MemberInfo role) + { + return Arrays.Contains(role); + } + + public bool IsDictionary(MemberInfo role) + { + return Dictionaries.Contains(role); + } + + public bool IsProperty(MemberInfo member) + { + return Properties.Contains(member); + } + + public bool IsDynamicComponent(MemberInfo member) + { + return DynamicComponents.Contains(member); + } + + public IEnumerable<string> GetPropertiesSplits(System.Type type) + { + return GetSplitGroupsFor(type); + } + } + + private readonly MixinDeclaredModel declaredModel; + private Func<System.Type, bool, bool> isEntity = (t, declared) => declared; private Func<System.Type, bool, bool> isRootEntity; private Func<System.Type, bool, bool> isTablePerClass; @@ -56,11 +199,12 @@ isDictionary = (m, declared) => declared || MatchCollection(m, MatchDictionaryMember); isManyToOne = (m, declared) => declared || MatchManyToOne(m); isOneToMany = (m, declared) => declared || MatchOneToMany(m); + declaredModel = new MixinDeclaredModel(this); } private bool MatchRootEntity(System.Type type) { - return type.IsClass && typeof(object).Equals(type.BaseType); + return type.IsClass && typeof(object).Equals(type.BaseType) && ((IModelInspector)this).IsEntity(type); } private bool MatchTablePerClass(System.Type type) @@ -213,6 +357,10 @@ const BindingFlags flattenHierarchyMembers = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + if (declaredModel.IsEntity(subject)) + { + return false; + } var modelInspector = (IModelInspector) this; return !subject.IsEnum && (subject.Namespace == null || !subject.Namespace.StartsWith("System")) /* hack */ && !modelInspector.IsEntity(subject) @@ -224,7 +372,10 @@ { const BindingFlags flattenHierarchyMembers = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - + if(declaredModel.Components.Contains(subject)) + { + return false; + } var modelInspector = (IModelInspector) this; return subject.IsClass && subject.GetProperties(flattenHierarchyMembers).Cast<MemberInfo>().Concat(subject.GetFields(flattenHierarchyMembers)).Any(m => modelInspector.IsPersistentId(m)); @@ -488,13 +639,13 @@ bool IModelInspector.IsRootEntity(System.Type type) { - bool declaredResult = declaredModel.IsRootEntity(type); + bool declaredResult = declaredModel.RootEntities.Contains(type); return isRootEntity(type, declaredResult); } bool IModelInspector.IsComponent(System.Type type) { - bool declaredResult = declaredModel.IsComponent(type); + bool declaredResult = declaredModel.Components.Contains(type); return isComponent(type, declaredResult); } Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-05-08 22:59:17 UTC (rev 5800) @@ -284,6 +284,7 @@ <Compile Include="Mapping\Any.cs" /> <Compile Include="Mapping\Array.cs" /> <Compile Include="Mapping\Bag.cs" /> + <Compile Include="Mapping\ByCode\AbstractExplicitlyDeclaredModel.cs" /> <Compile Include="Mapping\ByCode\CacheInclude.cs" /> <Compile Include="Mapping\ByCode\CacheUsage.cs" /> <Compile Include="Mapping\ByCode\Cascade.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/ComponentMappingRegistrationTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/ComponentMappingRegistrationTests.cs 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/ComponentMappingRegistrationTests.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -42,27 +42,39 @@ public void WhenRegisteredAsComponetThenCantRegisterAsJoinedSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsComponent(typeof(MyComponent)); + inspector.AddAsComponent(typeof (MyComponent)); - inspector.Executing(x => x.AddAsTablePerClassEntity(typeof(MyComponent))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerClassEntity(typeof (MyComponent)); + inspector.IsTablePerClass(typeof (MyComponent)); + }).Should().Throw<MappingException>(); } [Test] public void WhenRegisteredAsComponetThenCantRegisterAsSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsComponent(typeof(MyComponent)); + inspector.AddAsComponent(typeof (MyComponent)); - inspector.Executing(x => x.AddAsTablePerClassHierarchyEntity(typeof(MyComponent))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerClassHierarchyEntity(typeof (MyComponent)); + inspector.IsTablePerClassHierarchy(typeof (MyComponent)); + }).Should().Throw<MappingException>(); } [Test] public void WhenRegisteredAsComponetThenCantRegisterAsUnionSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsComponent(typeof(MyComponent)); + inspector.AddAsComponent(typeof (MyComponent)); - inspector.Executing(x => x.AddAsTablePerConcreteClassEntity(typeof(MyComponent))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerConcreteClassEntity(typeof (MyComponent)); + inspector.IsTablePerConcreteClass(typeof (MyComponent)); + }).Should().Throw<MappingException>(); } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/JoinedSubclassMappingStrategyTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/JoinedSubclassMappingStrategyTests.cs 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/JoinedSubclassMappingStrategyTests.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -47,20 +47,28 @@ public void WhenRegisteredAsJoinedSubclassThenCantRegisterAsSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.AddAsTablePerClassEntity(typeof(Inherited1)); + inspector.AddAsRootEntity(typeof (MyClass)); + inspector.AddAsTablePerClassEntity(typeof (Inherited1)); - inspector.Executing(x => x.AddAsTablePerClassHierarchyEntity(typeof(Inherited1))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerClassHierarchyEntity(typeof (Inherited1)); + inspector.IsTablePerClass(typeof (Inherited1)); + }).Should().Throw<MappingException>(); } [Test] public void WhenRegisteredAsJoinedSubclassThenCantRegisterAsUnionSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.AddAsTablePerClassEntity(typeof(Inherited1)); + inspector.AddAsRootEntity(typeof (MyClass)); + inspector.AddAsTablePerClassEntity(typeof (Inherited1)); - inspector.Executing(x => x.AddAsTablePerConcreteClassEntity(typeof(Inherited1))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerConcreteClassEntity(typeof (Inherited1)); + inspector.IsTablePerClass(typeof (Inherited1)); + }).Should().Throw<MappingException>(); } [Test] Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/RootClassMappingStrategyTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/RootClassMappingStrategyTests.cs 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/RootClassMappingStrategyTests.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -103,24 +103,36 @@ public void WhenRegisteredAsRootThenCantRegisterAsSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.Executing(x=> x.AddAsTablePerClassEntity(typeof(MyClass))).Throws<MappingException>(); + inspector.AddAsRootEntity(typeof (MyClass)); + Executing.This(() => + { + inspector.AddAsTablePerClassHierarchyEntity(typeof (MyClass)); + inspector.IsTablePerClassHierarchy(typeof (MyClass)); + }).Should().Throw<MappingException>(); } [Test] public void WhenRegisteredAsRootThenCantRegisterAsJoinedSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.Executing(x => x.AddAsTablePerClassEntity(typeof(MyClass))).Throws<MappingException>(); + inspector.AddAsRootEntity(typeof (MyClass)); + Executing.This(() => + { + inspector.AddAsTablePerClassEntity(typeof (MyClass)); + inspector.IsTablePerClass(typeof (MyClass)); + }).Should().Throw<MappingException>(); } [Test] public void WhenRegisteredAsRootThenCantRegisterAsUnionSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.Executing(x => x.AddAsTablePerClassEntity(typeof(MyClass))).Throws<MappingException>(); + inspector.AddAsRootEntity(typeof (MyClass)); + Executing.This(() => + { + inspector.AddAsTablePerConcreteClassEntity(typeof (MyClass)); + inspector.IsTablePerClass(typeof (MyClass)); + }).Should().Throw<MappingException>(); } [Test] @@ -131,5 +143,18 @@ inspector.IsEntity(typeof(MyClass)).Should().Be.True(); } + + [Test] + public void WhenMultipleRootRegisteredThenThrowsMappingException() + { + var inspector = new ExplicitlyDeclaredModel(); + inspector.AddAsRootEntity(typeof(MyClass)); + inspector.AddAsRootEntity(typeof(Inherited1)); + Executing.This(()=> + { + inspector.AddAsTablePerClassEntity(typeof(Inherited2)); + inspector.IsTablePerClass(typeof(Inherited2)); + }).Should().Throw<MappingException>(); + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/SubclassMappingStrategyTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/SubclassMappingStrategyTests.cs 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/SubclassMappingStrategyTests.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -50,17 +50,25 @@ inspector.AddAsRootEntity(typeof(MyClass)); inspector.AddAsTablePerClassHierarchyEntity(typeof(Inherited1)); - inspector.Executing(x => x.AddAsTablePerClassEntity(typeof(Inherited1))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerClassEntity(typeof(Inherited1)); + inspector.IsTablePerClass(typeof(Inherited1)); + }).Should().Throw<MappingException>(); } [Test] public void WhenRegisteredAsSubclassThenCantRegisterAsUnionSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.AddAsTablePerClassHierarchyEntity(typeof(Inherited1)); + inspector.AddAsRootEntity(typeof (MyClass)); + inspector.AddAsTablePerClassHierarchyEntity(typeof (Inherited1)); - inspector.Executing(x => x.AddAsTablePerConcreteClassEntity(typeof(Inherited1))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerConcreteClassEntity(typeof (Inherited1)); + inspector.IsTablePerClassHierarchy(typeof (Inherited1)); + }).Should().Throw<MappingException>(); } [Test] Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/UnionSubclassMappingStrategyTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/UnionSubclassMappingStrategyTests.cs 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExplicitlyDeclaredModelTests/UnionSubclassMappingStrategyTests.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -47,20 +47,28 @@ public void WhenRegisteredAsUnionSubclassThenCantRegisterAsSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.AddAsTablePerConcreteClassEntity(typeof(Inherited1)); + inspector.AddAsRootEntity(typeof (MyClass)); + inspector.AddAsTablePerConcreteClassEntity(typeof (Inherited1)); - inspector.Executing(x => x.AddAsTablePerClassHierarchyEntity(typeof(Inherited1))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerClassHierarchyEntity(typeof (Inherited1)); + inspector.IsTablePerConcreteClass(typeof (Inherited1)); + }).Should().Throw<MappingException>(); } [Test] public void WhenRegisteredAsUnionSubclassThenCantRegisterAsJoinedSubclass() { var inspector = new ExplicitlyDeclaredModel(); - inspector.AddAsRootEntity(typeof(MyClass)); - inspector.AddAsTablePerConcreteClassEntity(typeof(Inherited1)); + inspector.AddAsRootEntity(typeof (MyClass)); + inspector.AddAsTablePerConcreteClassEntity(typeof (Inherited1)); - inspector.Executing(x => x.AddAsTablePerClassEntity(typeof(Inherited1))).Throws<MappingException>(); + Executing.This(() => + { + inspector.AddAsTablePerClassEntity(typeof (Inherited1)); + inspector.IsTablePerConcreteClass(typeof (Inherited1)); + }).Should().Throw<MappingException>(); } [Test] Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/MixAutomapping/CallCustomConditions.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/MixAutomapping/CallCustomConditions.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/MixAutomapping/CallCustomConditions.cs 2011-05-08 22:59:17 UTC (rev 5800) @@ -0,0 +1,68 @@ +using System; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.MixAutomapping +{ + public class CallCustomConditions + { + public enum ActivityType + { + Form = 1, + Custom = 2, + Email = 3 + } + + private class Activity : Entity + { + public virtual string Title { get; set; } + } + + private interface IEntity<T> + { + T Id { get; } + } + + private class Entity : IEntity<Guid> + { + #region IEntity<Guid> Members + + public virtual Guid Id { get; private set; } + + #endregion + } + + private class FormActivity : Activity { } + + [Test] + public void WhenCustomizeConditionsThenUseCustomConditionsToRecognizeRootEntities() + { + System.Type baseEntityType = typeof(Entity); + var inspector = new SimpleModelInspector(); + inspector.IsEntity((t, declared) => baseEntityType.IsAssignableFrom(t) && baseEntityType != t && !t.IsInterface); + inspector.IsRootEntity((t, declared) => baseEntityType.Equals(t.BaseType)); + + var mapper = new ModelMapper(inspector); + mapper.Class<Entity>(map => map.Id(x => x.Id, + m => + { + m.Generator(Generators.Guid); + m.Column("ID"); + })); + + mapper.Class<Activity>(map => + { + map.Discriminator(dm => + { + dm.Column("DISCRIMINATOR_TYPE"); + dm.NotNullable(true); + }); + map.DiscriminatorValue(0); + }); + mapper.Subclass<FormActivity>(map => map.DiscriminatorValue(1)); + + mapper.Executing(m=> m.CompileMappingFor(new[] { typeof(Activity), typeof(FormActivity) })).NotThrows(); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-05-06 14:14:41 UTC (rev 5799) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-05-08 22:59:17 UTC (rev 5800) @@ -585,6 +585,7 @@ <Compile Include="MappingByCode\MappersTests\UnionSubclassMapperTests\TablesSincronizationTests.cs" /> <Compile Include="MappingByCode\MixAutomapping\ArrayCollectionTests.cs" /> <Compile Include="MappingByCode\MixAutomapping\BagCollectionTests.cs" /> + <Compile Include="MappingByCode\MixAutomapping\CallCustomConditions.cs" /> <Compile Include="MappingByCode\MixAutomapping\Compone... [truncated message content] |