protected void FillNameCollections(IEntityConfig entityConfig, ISet <String> memberNamesToIgnore, ISet <String> explicitBasicMemberNames, IList <IMemberConfig> embeddedMembers,
                                           IMap <String, IMemberConfig> nameToMemberConfig, IMap <String, IRelationConfig> nameToRelationConfig)
        {
            foreach (IMemberConfig memberConfig in entityConfig.GetMemberConfigIterable())
            {
                String memberName = memberConfig.Name;

                if (memberConfig.Ignore)
                {
                    memberNamesToIgnore.Add(memberName);
                    memberNamesToIgnore.Add(memberName + "Specified");
                    continue;
                }

                explicitBasicMemberNames.Add(memberName);

                String[] parts            = memberName.Split(dot);
                bool     isEmbeddedMember = parts.Length > 1;

                if (isEmbeddedMember)
                {
                    embeddedMembers.Add(memberConfig);
                    memberNamesToIgnore.Add(parts[0]);
                    memberNamesToIgnore.Add(parts[0] + "Specified");
                    continue;
                }

                nameToMemberConfig.Put(memberName, memberConfig);
            }

            foreach (IRelationConfig relationConfig in entityConfig.GetRelationConfigIterable())
            {
                String relationName = relationConfig.Name;

                nameToRelationConfig.Put(relationName, relationConfig);
            }
        }
        public void AddMembers(EntityMetaData metaData, IEntityConfig entityConfig)
        {
            Type realType = entityConfig.RealType;

            ISet <String>                      memberNamesToIgnore      = new HashSet <String>();
            ISet <String>                      explicitBasicMemberNames = new HashSet <String>();
            IList <IMemberConfig>              embeddedMembers          = new List <IMemberConfig>();
            IMap <String, IMemberConfig>       nameToMemberConfig       = new HashMap <String, IMemberConfig>();
            IMap <String, IRelationConfig>     nameToRelationConfig     = new HashMap <String, IRelationConfig>();
            IdentityLinkedMap <String, Member> nameToMemberMap          = new IdentityLinkedMap <String, Member>();

            FillNameCollections(entityConfig, memberNamesToIgnore, explicitBasicMemberNames, embeddedMembers, nameToMemberConfig, nameToRelationConfig);

            IdentityLinkedSet <PrimitiveMember> alternateIdMembers = new IdentityLinkedSet <PrimitiveMember>();
            IdentityLinkedSet <PrimitiveMember> primitiveMembers   = new IdentityLinkedSet <PrimitiveMember>();
            IdentityLinkedSet <RelationMember>  relationMembers    = new IdentityLinkedSet <RelationMember>();
            IdentityLinkedSet <Member>          notMergeRelevant   = new IdentityLinkedSet <Member>();

            IdentityLinkedSet <Member> containedInAlternateIdMember = new IdentityLinkedSet <Member>();

            IPropertyInfo[] properties = PropertyInfoProvider.GetProperties(realType);

            IdentityLinkedMap <String, Member> explicitlyConfiguredMemberNameToMember = new IdentityLinkedMap <String, Member>();

            HashMap <String, IOrmConfig> nameToConfigMap = new HashMap <String, IOrmConfig>();

            // Resolve members for all explicit configurations - both simple and composite ones, each with embedded
            // functionality (dot-member-path)
            foreach (IMemberConfig memberConfig in entityConfig.GetMemberConfigIterable())
            {
                PutNameToConfigMap(memberConfig, nameToConfigMap);
                if (memberConfig.Ignore)
                {
                    continue;
                }
                HandleMemberConfig(metaData, realType, memberConfig, explicitlyConfiguredMemberNameToMember, nameToMemberMap);
            }
            foreach (IRelationConfig relationConfig in entityConfig.GetRelationConfigIterable())
            {
                PutNameToConfigMap(relationConfig, nameToConfigMap);
                HandleRelationConfig(realType, relationConfig, explicitlyConfiguredMemberNameToMember);
            }
            PutNameToConfigMap(entityConfig.IdMemberConfig, nameToConfigMap);
            PutNameToConfigMap(entityConfig.VersionMemberConfig, nameToConfigMap);
            PutNameToConfigMap(entityConfig.CreatedByMemberConfig, nameToConfigMap);
            PutNameToConfigMap(entityConfig.CreatedOnMemberConfig, nameToConfigMap);
            PutNameToConfigMap(entityConfig.UpdatedByMemberConfig, nameToConfigMap);
            PutNameToConfigMap(entityConfig.UpdatedOnMemberConfig, nameToConfigMap);

            metaData.IdMember        = HandleMemberConfig(metaData, realType, entityConfig.IdMemberConfig, explicitlyConfiguredMemberNameToMember, nameToMemberMap);
            metaData.VersionMember   = HandleMemberConfig(metaData, realType, entityConfig.VersionMemberConfig, explicitlyConfiguredMemberNameToMember, nameToMemberMap);
            metaData.CreatedByMember = HandleMemberConfig(metaData, realType, entityConfig.CreatedByMemberConfig, explicitlyConfiguredMemberNameToMember, nameToMemberMap);
            metaData.CreatedOnMember = HandleMemberConfig(metaData, realType, entityConfig.CreatedOnMemberConfig, explicitlyConfiguredMemberNameToMember, nameToMemberMap);
            metaData.UpdatedByMember = HandleMemberConfig(metaData, realType, entityConfig.UpdatedByMemberConfig, explicitlyConfiguredMemberNameToMember, nameToMemberMap);
            metaData.UpdatedOnMember = HandleMemberConfig(metaData, realType, entityConfig.UpdatedOnMemberConfig, explicitlyConfiguredMemberNameToMember, nameToMemberMap);

            IdentityHashSet <Member> idMembers = new IdentityHashSet <Member>();
            Member idMember = metaData.IdMember;

            if (idMember is CompositeIdMember)
            {
                idMembers.AddAll(((CompositeIdMember)idMember).Members);
            }
            else
            {
                idMembers.Add(idMember);
            }

            // Handle all explicitly configured members
            foreach (Entry <String, Member> entry in explicitlyConfiguredMemberNameToMember)
            {
                String     memberName = entry.Key;
                IOrmConfig ormConfig  = nameToConfigMap.Get(memberName);

                Member member = entry.Value;

                if (idMembers.Contains(member))
                {
                    continue;
                }
                if (ormConfig.ExplicitlyNotMergeRelevant)
                {
                    notMergeRelevant.Add(member);
                }
                if (ormConfig is IRelationConfig)
                {
                    if (!relationMembers.Add((RelationMember)member))
                    {
                        throw new Exception("Member has been registered as relation multiple times: " + member.Name);
                    }
                    continue;
                }
                if (!(ormConfig is IMemberConfig))
                {
                    continue;
                }
                if (((IMemberConfig)ormConfig).AlternateId)
                {
                    if (!alternateIdMembers.Add((PrimitiveMember)member))
                    {
                        throw new Exception("Member has been registered as alternate id multiple times: " + member.Name);
                    }
                    if (member is CompositeIdMember)
                    {
                        Member[] containedMembers = ((CompositeIdMember)member).Members;
                        containedInAlternateIdMember.AddAll(containedMembers);
                    }
                }
                if (!(member is CompositeIdMember) && metaData.VersionMember != member)
                {
                    // Alternate Ids are normally primitives, too. But Composite Alternate Ids not - only their composite
                    // items are primitives
                    primitiveMembers.Add((PrimitiveMember)member);
                }
            }
            IdentityHashSet <String> explicitTypeInfoItems = IdentityHashSet <String> .Create(explicitlyConfiguredMemberNameToMember.Count);

            foreach (Entry <String, Member> entry in explicitlyConfiguredMemberNameToMember)
            {
                Member member = entry.Value;
                explicitTypeInfoItems.Add(member.Name);
                if (member is IEmbeddedMember)
                {
                    explicitTypeInfoItems.Add(((IEmbeddedMember)member).GetMemberPath()[0].Name);
                }
            }
            // Go through the available members to look for potential auto-mapping (simple, no embedded)
            for (int i = 0; i < properties.Length; i++)
            {
                IPropertyInfo property   = properties[i];
                String        memberName = property.Name;
                if (memberNamesToIgnore.Contains(memberName))
                {
                    continue;
                }
                if (explicitTypeInfoItems.Contains(memberName))
                {
                    // already configured, no auto mapping needed for this member
                    continue;
                }

                MethodPropertyInfo mProperty = (MethodPropertyInfo)property;
                Type elementType             = TypeInfoItemUtil.GetElementTypeUsingReflection(mProperty.Getter.ReturnType, null);
                if ((nameToMemberMap.Get(property.Name) is RelationMember) || RelationProvider.IsEntityType(elementType))
                {
                    RelationMember member = GetRelationMember(metaData.EntityType, property, nameToMemberMap);
                    relationMembers.Add(member);
                    continue;
                }
                PrimitiveMember member2 = GetPrimitiveMember(metaData.EntityType, property, nameToMemberMap);
                if (metaData.IdMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_ID))
                {
                    metaData.IdMember = member2;
                    continue;
                }
                if (idMembers.Contains(member2) && !alternateIdMembers.Contains(member2) && !containedInAlternateIdMember.Contains(member2))
                {
                    continue;
                }
                if (member2.Equals(metaData.IdMember) || member2.Equals(metaData.VersionMember) || member2.Equals(metaData.CreatedByMember) ||
                    member2.Equals(metaData.CreatedOnMember) || member2.Equals(metaData.UpdatedByMember) || member2.Equals(metaData.UpdatedOnMember))
                {
                    continue;
                }
                if (metaData.VersionMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_VERSION))
                {
                    metaData.VersionMember = member2;
                    continue;
                }
                if (metaData.CreatedByMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_CREATED_BY))
                {
                    metaData.CreatedByMember = member2;
                }
                else if (metaData.CreatedOnMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_CREATED_ON))
                {
                    metaData.CreatedOnMember = member2;
                }
                else if (metaData.UpdatedByMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_UPDATED_BY))
                {
                    metaData.UpdatedByMember = member2;
                }
                else if (metaData.UpdatedOnMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_UPDATED_ON))
                {
                    metaData.UpdatedOnMember = member2;
                }
                primitiveMembers.Add(member2);
            }
            foreach (PrimitiveMember member in primitiveMembers)
            {
                String memberName = member.Name;
                if (explicitBasicMemberNames.Contains(memberName))
                {
                    // Even if the name would match, this member was explicitly configured as "basic"
                    continue;
                }
                if (metaData.CreatedByMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_CREATED_BY))
                {
                    metaData.CreatedByMember = member;
                }
                else if (metaData.CreatedOnMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_CREATED_ON))
                {
                    metaData.CreatedOnMember = member;
                }
                else if (metaData.UpdatedByMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_UPDATED_BY))
                {
                    metaData.UpdatedByMember = member;
                }
                else if (metaData.UpdatedOnMember == null && memberName.Equals(EntityMetaData.DEFAULT_NAME_UPDATED_ON))
                {
                    metaData.UpdatedOnMember = member;
                }
            }
            FilterWrongRelationMappings(relationMembers);
            // Order of setter calls is important
            PrimitiveMember[] primitives   = primitiveMembers.ToArray();
            PrimitiveMember[] alternateIds = alternateIdMembers.ToArray();
            RelationMember[]  relations    = relationMembers.ToArray();
            Array.Sort(primitives);
            Array.Sort(alternateIds);
            Array.Sort(relations);
            metaData.PrimitiveMembers   = primitives;
            metaData.AlternateIdMembers = alternateIds;
            metaData.RelationMembers    = relations;

            foreach (Member member in notMergeRelevant)
            {
                metaData.SetMergeRelevant(member, false);
            }
            if (metaData.IdMember == null)
            {
                throw new Exception("No ID member could be resolved for entity of type " + metaData.RealType);
            }
        }