private void ProcessManyToOneReference(
			Entity entity,
			DirectedReference directedReference,
			Action<object> addItem,
			string cascade,
			string collectionCascade,
			string lazy,
			string orderByClause,
			bool inverse)
        {
            if (directedReference.FromEndEnabled == false) return;

            ITable referenceMappedTable = directedReference.Reference.MappedTable();
            DirectedRelationship directedRelationship = null;

            if (referenceMappedTable == null)
                directedRelationship = GetDirectedMappedRelationship(entity, directedReference.Reference);

            if (directedReference.FromEndCardinality == Cardinality.One)
            {
                fetchMode fetchMode;
                bool insert;
                bool update;

                if (directedReference.Entity1IsFromEnd)
                {
                    fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd1FetchMode().ToString(), true);
                    insert = directedReference.Reference.GetReferenceEnd1Insert();
                    update = directedReference.Reference.GetReferenceEnd1Update();
                }
                else
                {
                    fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd2FetchMode().ToString(), true);
                    insert = directedReference.Reference.GetReferenceEnd2Insert();
                    update = directedReference.Reference.GetReferenceEnd2Update();
                }
                manytoone manyToOneNode;

                if (referenceMappedTable == null)
                    manyToOneNode = CreateManyToOneNode(directedReference, directedRelationship, cascade);
                else
                    manyToOneNode = CreateManyToOneNode(directedReference, referenceMappedTable);

                manyToOneNode.fetch = fetchMode;
                manyToOneNode.fetchSpecified = true;
                manyToOneNode.insert = insert;
                manyToOneNode.update = update;

                addItem(manyToOneNode);
            }
            else
            {
                key keyNode = new key();

                if (referenceMappedTable == null &&
                    directedRelationship.ToKey.Columns.Count > 1)
                {
                    foreach (var columnNode in GetColumnNodes(directedRelationship.ToKey.Columns))
                        keyNode.AddColumn(columnNode);
                }
                else if (referenceMappedTable != null)
                {
                    ITable toPrimaryMappedTable = EntityMapper.GetPrimaryTable(directedReference.ToEntity);
                    var toColumnsInPrimaryKey = referenceMappedTable.Relationships.First(t => t.PrimaryTable == toPrimaryMappedTable || t.ForeignTable == toPrimaryMappedTable).ForeignKey.Columns;

                    foreach (var columnNode in GetColumnNodes(toColumnsInPrimaryKey))
                        keyNode.AddColumn(columnNode);
                }
                else
                    keyNode.column1 = directedRelationship.ToKey.Columns[0].Name.BackTick();

                onetomany oneToManyNode = new onetomany();
                oneToManyNode.@class = directedReference.ToEntity.Name;

                collectionFetchMode collFetchMode;

                if (directedReference.Entity1IsFromEnd)
                    collFetchMode = (collectionFetchMode)Enum.Parse(typeof(collectionFetchMode), directedReference.Reference.GetReferenceEnd1CollectionFetchMode().ToString(), true);
                else
                    collFetchMode = (collectionFetchMode)Enum.Parse(typeof(collectionFetchMode), directedReference.Reference.GetReferenceEnd2CollectionFetchMode().ToString(), true);

                AssociationType type = NHCollections.GetAssociationType(directedReference);

                switch (type)
                {
                    case AssociationType.None:
                        Log.WarnFormat("No association type was set on reference {0} for the end {1}. This is usually an error.", directedReference.Reference.Name, directedReference.Entity1IsFromEnd ? "1" : "2");
                        return;
                    case AssociationType.Set:
                        var set = CreateSetNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                        set.Item = oneToManyNode;

                        if (orderByClause.Length > 0)
                            set.orderby = orderByClause;

                        addItem(set);
                        break;
                    case AssociationType.Map:
                        var mapNode = CreateMapNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                        mapNode.Item = new index
                        {
                            column1 = NHCollections.GetIndexColumnName(directedReference),
                            type = NHCollections.GetIndexColumnTypeName(directedReference, EntityMapper.GetPrimaryTable(directedReference.ToEntity))
                        };
                        mapNode.Item1 = oneToManyNode;

                        if (orderByClause.Length > 0)
                            mapNode.orderby = orderByClause;

                        addItem(mapNode);
                        break;
                    case AssociationType.Bag:
                        var bag = CreateBagNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                        bag.Item = oneToManyNode;

                        if (orderByClause.Length > 0)
                            bag.orderby = orderByClause;

                        addItem(bag);
                        break;
                    case AssociationType.List:
                        list listNode = CreateListNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                        listNode.Item = new index { column1 = NHCollections.GetIndexColumnName(directedReference) };
                        listNode.Item1 = oneToManyNode;

                        if (orderByClause.Length > 0)
                            listNode.orderby = orderByClause;

                        addItem(listNode);
                        break;
                    case AssociationType.IDBag:
                        idbag idbagNode = CreateIdBagNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                        idbagNode.collectionid = new collectionid
                        {
                            column1 = NHCollections.GetIndexColumnName(directedReference),
                            generator = new generator { @class = "sequence" },
                            type = NHCollections.GetIndexColumnTypeName(directedReference, EntityMapper.GetPrimaryTable(directedReference.ToEntity))
                        };

                        addItem(idbagNode);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException("AssociationType not handled yet: " + type.ToString());
                }
            }
        }
        private void ProcessOneToOneReference(Entity entity, DirectedReference directedReference, Action<object> addItem, string cascade, string lazy)
        {
            if (directedReference.FromEndEnabled == false) return;

            DirectedRelationship directedRelationship = GetDirectedMappedRelationship(entity, directedReference.Reference);

            fetchMode fetchMode;

            if (directedReference.Entity1IsFromEnd)
                fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd1FetchMode().ToString(), true);
            else
                fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd2FetchMode().ToString(), true);

            // if this side has the foreign key, it gets the many to one node
            if (directedRelationship.FromKey.Keytype == DatabaseKeyType.Foreign)
            {
                manytoone manyToOneNode = CreateManyToOneNode(directedReference, directedRelationship, cascade);
                manyToOneNode.unique = true;
                manyToOneNode.fetch = fetchMode;
                manyToOneNode.fetchSpecified = true;

                addItem(manyToOneNode);
            }
            else
            {
                onetoone oneToOneNode = new onetoone();
                oneToOneNode.@class = directedReference.ToEntity.Name;
                oneToOneNode.name = directedReference.FromName;
                oneToOneNode.propertyref = directedReference.ToName;
                oneToOneNode.fetch = fetchMode;
                oneToOneNode.fetchSpecified = true;

                addItem(oneToOneNode);
            }
        }
        private set CreateSetNode(DirectedReference reference, key keyNode, string cascade, collectionFetchMode colFetchMode, string lazyString, bool inverse)
        {
            var lazy = (collectionLazy)Enum.Parse(typeof(collectionLazy), lazyString.ToString().Replace("_", ""), true);

            set setNode = new set();
            setNode.name = reference.FromName;
            setNode.key = keyNode;
            setNode.cascade = cascade == "none" ? null : cascade;
            setNode.inverse = inverse;

            setNode.fetchSpecified = colFetchMode != collectionFetchMode.select;
            setNode.fetch = colFetchMode;
            setNode.lazySpecified = lazy != collectionLazy.@true;
            setNode.lazy = (collectionLazy)Enum.Parse(typeof(collectionLazy), lazy.ToString().Replace("_", ""), true);

            var sqlWhereClause = NHCollections.GetSqlWhereClause(reference);

            if (string.IsNullOrEmpty(sqlWhereClause) == false)
                setNode.where = sqlWhereClause;

            return setNode;
        }
        private void ProcessManyToManyReference(
			Entity entity,
			DirectedReference directedReference,
			Action<object> addItem,
			Dictionary<ITable, int> manyToManySameTableProcessingCounts,
			string collectionCascade,
			string lazy,
			string orderByClause,
			bool inverse)
        {
            if (directedReference.FromEndEnabled == false) return;

            ITable referenceMappedTable = directedReference.Reference.MappedTable();

            ITable fromPrimaryMappedTable = EntityMapper.GetPrimaryTable(entity);
            ITable toPrimaryMappedTable = EntityMapper.GetPrimaryTable(directedReference.ToEntity);
            Cardinality cardinalityPrimary;
            Cardinality cardinalityForeign;
            IKey mainKey;
            IKey associationKey;
            ITable associationTable = entity.GetAssociationTable(directedReference.ToEntity, out cardinalityPrimary, out cardinalityForeign, out mainKey, out associationKey);

            key keyNode = new key();
            List<IColumn> fromInPrimaryKey = new List<IColumn>();
            List<IColumn> toInPrimaryKey = new List<IColumn>();

            if (fromPrimaryMappedTable == toPrimaryMappedTable)
            {
                // This many-to-many relationship is to the same table
                if (manyToManySameTableProcessingCounts.ContainsKey(toPrimaryMappedTable))
                {
                    int index = manyToManySameTableProcessingCounts[toPrimaryMappedTable];
                    index++;
                    fromInPrimaryKey.AddRange(referenceMappedTable.Relationships.Where(t => t.PrimaryTable == fromPrimaryMappedTable).ElementAt(index).PrimaryKey.Columns);
                    toInPrimaryKey.AddRange(referenceMappedTable.Relationships.Where(t => t.PrimaryTable == toPrimaryMappedTable).ElementAt(index).ForeignKey.Columns);
                    manyToManySameTableProcessingCounts[toPrimaryMappedTable] = index;
                }
                else
                {
                    fromInPrimaryKey.AddRange(referenceMappedTable.Relationships.Where(t => t.PrimaryTable == fromPrimaryMappedTable).ElementAt(0).PrimaryKey.Columns);
                    toInPrimaryKey.AddRange(referenceMappedTable.Relationships.Where(t => t.PrimaryTable == toPrimaryMappedTable).ElementAt(0).ForeignKey.Columns);
                    manyToManySameTableProcessingCounts.Add(toPrimaryMappedTable, 0);
                }
            }
            else
            {
                foreach (var coll in referenceMappedTable.Relationships.Where(t => t.PrimaryTable == fromPrimaryMappedTable).Select(r => r.ForeignKey.Columns))
                    foreach (var c in coll)
                        fromInPrimaryKey.Add(c);

                foreach (var coll in referenceMappedTable.Relationships.Where(t => t.PrimaryTable == toPrimaryMappedTable).Select(r => r.ForeignKey.Columns))
                    foreach (var c in coll)
                        toInPrimaryKey.Add(c);
            }

            if (fromInPrimaryKey.Count() == 1)
                keyNode.column1 = fromInPrimaryKey.First().Name.BackTick();
            else
                foreach (var columnNode in GetColumnNodes(fromInPrimaryKey))
                    keyNode.AddColumn(columnNode);

            manytomany manyToManyNode = new manytomany();
            manyToManyNode.@class = directedReference.ToEntity.Name;

            if (toInPrimaryKey.Count() == 1)
                manyToManyNode.column = toInPrimaryKey.First().Name.BackTick();
            else
                foreach (var columnNode in GetColumnNodes(toInPrimaryKey))
                    keyNode.AddColumn(columnNode);

            collectionFetchMode collFetchMode;

            if (directedReference.Entity1IsFromEnd)
                collFetchMode = (collectionFetchMode)Enum.Parse(typeof(collectionFetchMode), directedReference.Reference.GetReferenceEnd1CollectionFetchMode().ToString(), true);
            else
                collFetchMode = (collectionFetchMode)Enum.Parse(typeof(collectionFetchMode), directedReference.Reference.GetReferenceEnd2CollectionFetchMode().ToString(), true);

            AssociationType type = NHCollections.GetAssociationType(directedReference);

            switch (type)
            {
                case AssociationType.None:
                    Log.WarnFormat("No association type was set on reference {0} for the end {1}. This is usually an error.", directedReference.Reference.Name, directedReference.Entity1IsFromEnd ? "One" : "Two");
                    return;
                case AssociationType.Set:
                    set setNode = CreateSetNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                    setNode.table = referenceMappedTable.Name.BackTick();
                    setNode.Item = manyToManyNode;

                    if (orderByClause.Length > 0)
                        setNode.orderby = orderByClause;

                    addItem(setNode);
                    break;
                case AssociationType.Bag:
                    bag bagNode = CreateBagNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                    bagNode.table = referenceMappedTable.Name.BackTick();
                    bagNode.Item = manyToManyNode;

                    if (orderByClause.Length > 0)
                        bagNode.orderby = orderByClause;

                    addItem(bagNode);
                    break;
                case AssociationType.Map:
                    map mapNode = CreateMapNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                    mapNode.table = referenceMappedTable.Name.BackTick();
                    mapNode.Item = new index
                                        {
                                            column1 = NHCollections.GetIndexColumnName(directedReference),
                                            type = NHCollections.GetIndexColumnTypeName(directedReference, toPrimaryMappedTable /*fromPrimaryMappedTable*/)
                                        };
                    mapNode.Item1 = manyToManyNode;

                    if (orderByClause.Length > 0)
                        mapNode.orderby = orderByClause;

                    addItem(mapNode);
                    break;
                case AssociationType.List:
                    list listNode = CreateListNode(directedReference, keyNode, collectionCascade, collFetchMode, lazy, inverse);
                    listNode.table = referenceMappedTable.Name.BackTick();
                    listNode.Item = new index
                    {
                        column1 = NHCollections.GetIndexColumnName(directedReference),
                    };
                    listNode.Item1 = manyToManyNode;

                    if (orderByClause.Length > 0)
                        listNode.orderby = orderByClause;

                    addItem(listNode);
                    break;
                // case AssociationType.IDBag:
                //     throw new NotImplementedException(
                //         string.Format("Have not implemented {0} association type for Many To Many relationships", type));
                default:
                    throw new NotImplementedException("AssociationType not handled yet: " + type.ToString());
            }
        }
        private manytoone CreateManyToOneNode(DirectedReference directedReference, ITable referenceMappedTable)
        {
            fetchMode fetchMode;
            bool insert;
            bool update;

            if (directedReference.Entity1IsFromEnd)
            {
                fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd1FetchMode().ToString(), true);
                insert = directedReference.Reference.GetReferenceEnd1Insert();
                update = directedReference.Reference.GetReferenceEnd1Update();
            }
            else
            {
                fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd2FetchMode().ToString(), true);
                insert = directedReference.Reference.GetReferenceEnd2Insert();
                update = directedReference.Reference.GetReferenceEnd2Update();
            }
            manytoone manyToOneNode = new manytoone();
            manyToOneNode.@class = directedReference.ToEntity.Name;
            manyToOneNode.name = directedReference.FromName;
            //bool notNullableColumnsExist = directedRelationship.MappedColumns.Any(mc => !mc.Source.IsNullable);
            manyToOneNode.notnull = true;
            manyToOneNode.notnullSpecified = true;
            manyToOneNode.fetch = fetchMode;
            manyToOneNode.fetchSpecified = true;
            manyToOneNode.insert = insert;
            manyToOneNode.update = update;

            ITable fromPrimaryMappedTable = EntityMapper.GetPrimaryTable(directedReference.FromEntity);
            List<IColumn> fromKeyColumns = referenceMappedTable.Relationships.First(t => t.PrimaryTable == fromPrimaryMappedTable || t.ForeignTable == fromPrimaryMappedTable).ForeignKey.Columns.ToList();

            if (fromKeyColumns.Count > 1)
                foreach (var columnNode in GetColumnNodes(fromKeyColumns))
                    manyToOneNode.AddColumn(columnNode);
            else
                manyToOneNode.column = fromKeyColumns[0].Name.BackTick();

            return manyToOneNode;
        }
        private manytoone CreateManyToOneNode(DirectedReference directedReference, DirectedRelationship directedRelationship, string cascade)
        {
            fetchMode fetchMode;
            bool insert;
            bool update;

            if (directedReference.Entity1IsFromEnd)
            {
                fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd1FetchMode().ToString(), true);
                insert = directedReference.Reference.GetReferenceEnd1Insert();
                update = directedReference.Reference.GetReferenceEnd1Update();
            }
            else
            {
                fetchMode = (fetchMode)Enum.Parse(typeof(fetchMode), directedReference.Reference.GetReferenceEnd2FetchMode().ToString(), true);
                insert = directedReference.Reference.GetReferenceEnd2Insert();
                update = directedReference.Reference.GetReferenceEnd2Update();
            }
            manytoone manyToOneNode = new manytoone();
            manyToOneNode.@class = directedReference.ToEntity.Name;
            manyToOneNode.name = directedReference.FromName;
            bool notNullableColumnsExist = directedRelationship.MappedColumns.Any(mc => !mc.Source.IsNullable);
            manyToOneNode.notnull = notNullableColumnsExist;
            manyToOneNode.notnullSpecified = true;
            manyToOneNode.fetch = fetchMode;
            manyToOneNode.fetchSpecified = true;
            manyToOneNode.insert = insert;
            manyToOneNode.update = update;
            manyToOneNode.cascade = cascade == "none" ? null : cascade;

            if (directedRelationship.ToTable == directedRelationship.FromTable)
            {
                if (directedRelationship.ToKey.Keytype == Providers.EntityModel.Helper.DatabaseKeyType.Primary)
                    if (directedRelationship.FromKey.Columns.Count > 1)
                        foreach (var column in GetColumnNodes(directedRelationship.FromKey.Columns))
                            manyToOneNode.AddColumn(column);
                    else
                        manyToOneNode.column = directedRelationship.FromKey.Columns[0].Name.BackTick();
                else
                    if (directedRelationship.ToKey.Columns.Count > 1)
                        foreach (var column in GetColumnNodes(directedRelationship.ToKey.Columns))
                            manyToOneNode.AddColumn(column);
                    else
                        manyToOneNode.column = directedRelationship.ToKey.Columns[0].Name.BackTick();
            }
            else
            {
                if (directedRelationship.FromKey.Columns.Count > 1)
                    foreach (var column in GetColumnNodes(directedRelationship.FromKey.Columns))
                        manyToOneNode.AddColumn(column);
                else
                    manyToOneNode.column = directedRelationship.FromKey.Columns[0].Name.BackTick();
            }
            return manyToOneNode;
        }
        private void mnuMergeEntity_Click(object sender, EventArgs e)
        {
            BusyPopulating = true;

            try
            {
                DirectedReference dr = new DirectedReference(TheEntity, SelectedReference);
                Entity entityToMerge = dr.ToEntity;
                List<ITable> mappedTables = entityToMerge.MappedTables().ToList();

                foreach (var table in mappedTables)
                    foreach (var column in table.Columns)
                    {
                        Property newProperty = Controller.MappingLayer.OneToOneEntityProcessor.CreatePropertyFromColumn(column);
                        newProperty.Name = newProperty.Name.GetNextName(TheEntity.Properties.Select(p => p.Name));
                        TheEntity.AddProperty(newProperty);
                        newProperty.SetMappedColumn(column);
                    }
                entityToMerge.DeleteSelf();
            }
            finally
            {
                BusyPopulating = false;
                Populate();
            }
        }
        public static string ProcessReferenceTemplate(Entity entity, DirectedReference reference)
        {
            System.Text.StringBuilder sb = new StringBuilder(((SourceCodeMultiLineType)SharedData.CurrentProject.GetUserOption("ReferenceTemplate")).Value);

            string typeName;

            if (reference.FromEndCardinality == ArchAngel.Interfaces.Cardinality.Many)
                typeName = NHCollections.GetCollectionType(reference).Replace(SharedData.CurrentProject.GetUserOption("ProjectNamespace").ToString() + ".Model.", "");
            else
                typeName = reference.ToEntity.Name;

            sb.Replace("#entity.Name#", entity.Name);
            sb.Replace("#reference.Name#", reference.FromName);
            sb.Replace("#reference.Type#", typeName);

            bool usePrivateSetter = (bool)SharedData.CurrentProject.GetUserOption("UsePrivateSettersOnProperties") ||
                                    (reference.Entity1IsFromEnd ? (bool)reference.Reference.GetUserOptionValue("End1UsePrivateSetter") : (bool)reference.Reference.GetUserOptionValue("End2UsePrivateSetter"));

            ProcessIfStatement(sb, "reference.SetterIsPrivate", usePrivateSetter);

            return RemoveTrailingLineBreaks(sb.ToString());
        }
        private static void ProcessOneToManyReference(MappingSet set, Reference reference)
        {
            var manyEnd = reference.Cardinality1 == Cardinality.Many ? reference.Entity1 : reference.Entity2;
            var directedRef = new DirectedReference(manyEnd, reference);

            var oneEnd = directedRef.ToEntity;
            var oneEndTable = oneEnd.MappedTables().First();
            var manyEndTable = manyEnd.MappedTables().First();

            IKey primaryKey = oneEndTable.FirstPrimaryKey;
            // Create a foreign key on the Many side
            Key foreignKey = CreateForeignKey(set, oneEndTable, manyEndTable);

            // Create the relationship between the two.
            var relationship = oneEndTable.CreateRelationshipUsing(primaryKey, foreignKey);

            set.ChangeMappingFor(reference).To(relationship);
        }