protected virtual void WriteClass(CodeWriter writer, Table table, Database schema, GenerationContext context)
        {
            writer.WriteLine();

            string entityBase = context.Parameters.EntityBase;
            if (string.IsNullOrEmpty(entityBase))
                entityBase = schema.EntityBase;

            var specifications = SpecificationDefinition.Partial;
            if (table.Type.AccessModifierSpecified)
                specifications |= GetSpecificationDefinition(table.Type.AccessModifier);
            else
                specifications |= SpecificationDefinition.Public;
            if (table.Type.ModifierSpecified)
                specifications |= GetSpecificationDefinition(table.Type.Modifier);

            var tableAttribute = NewAttributeDefinition<TableAttribute>();
            tableAttribute["Name"] = table.Name;
            using (writer.WriteAttribute(tableAttribute))
            using (writer.WriteClass(specifications,
                                     table.Type.Name, entityBase, context.Parameters.EntityInterfaces))
            {
                WriteClassHeader(writer, table, context);
                WriteCustomTypes(writer, table, schema, context);
                WriteClassExtensibilityDeclarations(writer, table, context);
                WriteClassProperties(writer, table, context);
                if (context.Parameters.GenerateEqualsHash)
                    WriteClassEqualsAndHash(writer, table, context);
                WriteClassChildren(writer, table, schema, context);
                WriteClassParents(writer, table, schema, context);
                WriteClassChildrenAttachment(writer, table, schema, context);
                WriteClassCtor(writer, table, schema, context);
            }
        }
        protected override void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)
        {
            var constraints = ReadConstraints(conn, schemaName.DbName);

            //sort tables - parents first (this is moving to SchemaPostprocess)
            //TableSorter.Sort(tables, constraints);

            foreach (DataConstraint keyColRow in constraints)
            {
                //find my table:
                string fullKeyDbName           = GetFullDbName(keyColRow.TableName, keyColRow.TableSchema);
                DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => fullKeyDbName == t.Name);
                if (table == null)
                {
                    bool ignoreCase = true;
                    table = schema.Tables.FirstOrDefault(t => 0 == string.Compare(fullKeyDbName, t.Name, ignoreCase));
                    if (table == null)
                    {
                        WriteErrorLine("ERROR L46: Table '" + keyColRow.TableName + "' not found for column " + keyColRow.ColumnName);
                        continue;
                    }
                }

                bool isForeignKey = keyColRow.ConstraintName != "PRIMARY" &&
                                    keyColRow.ReferencedTableName != null;

                if (isForeignKey)
                {
                    LoadForeignKey(schema, table, keyColRow.ColumnName, keyColRow.TableName, keyColRow.TableSchema,
                                   keyColRow.ReferencedColumnName, keyColRow.ReferencedTableName, keyColRow.ReferencedTableSchema,
                                   keyColRow.ConstraintName, nameFormat, names);
                }
            }
        }
Beispiel #3
0
        protected override void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)
        {
            //TableSorter.Sort(tables, constraints); //sort tables - parents first

            var constraints = ReadConstraints(conn, schemaName.DbName);

            var allKeys2    = ReadForeignConstraints(conn, schemaName.DbName);
            var foreignKeys = allKeys2.Where(k => k.ConstraintType == "FOREIGN KEY").ToList();
            var primaryKeys = allKeys2.Where(k => k.ConstraintType == "PRIMARY KEY").ToList();


            foreach (DataConstraint keyColRow in constraints)
            {
                //find my table:
                string constraintFullDbName    = GetFullDbName(keyColRow.TableName, keyColRow.TableSchema);
                DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => constraintFullDbName == t.Name);
                if (table == null)
                {
                    WriteErrorLine("ERROR L138: Table '" + keyColRow.TableName + "' not found for column " + keyColRow.ColumnName);
                    continue;
                }

                //todo: must understand better how PKEYs are encoded.
                //In Sasha's DB, they don't end with "_pkey", you need to rely on ReadForeignConstraints().
                //In Northwind, they do end with "_pkey".
                bool isPrimaryKey = keyColRow.ConstraintName.EndsWith("_pkey") ||
                                    primaryKeys.Count(k => k.ConstraintName == keyColRow.ConstraintName) == 1;

                if (isPrimaryKey)
                {
                    //A) add primary key
                    DbLinq.Schema.Dbml.Column primaryKeyCol = table.Type.Columns.First(c => c.Name == keyColRow.ColumnName);
                    primaryKeyCol.IsPrimaryKey = true;
                }
                else
                {
                    DataForeignConstraint dataForeignConstraint = foreignKeys.FirstOrDefault(f => f.ConstraintName == keyColRow.ConstraintName);

                    if (dataForeignConstraint == null)
                    {
                        string msg = "Missing data from 'constraint_column_usage' for foreign key " + keyColRow.ConstraintName;
                        WriteErrorLine(msg);
                        //throw new ApplicationException(msg);
                        continue; //as per Andrus, do not throw. //putting together an Adnrus_DB test case.
                    }

                    LoadForeignKey(schema, table, keyColRow.ColumnName, keyColRow.TableName, keyColRow.TableSchema,
                                   dataForeignConstraint.ColumnName, dataForeignConstraint.ReferencedTableName,
                                   dataForeignConstraint.ReferencedTableSchema,
                                   keyColRow.ConstraintName, nameFormat, names);
                }
            }
        }
        /// <summary>
        /// Loads the foreign key.
        /// </summary>
        /// <param name="schema">The schema.</param>
        /// <param name="table">The table.</param>
        /// <param name="columnName">Name of the column.</param>
        /// <param name="tableName">Name of the table.</param>
        /// <param name="tableSchema">The table schema.</param>
        /// <param name="referencedColumnName">Name of the referenced column.</param>
        /// <param name="referencedTableName">Name of the referenced table.</param>
        /// <param name="referencedTableSchema">The referenced table schema.</param>
        /// <param name="constraintName">Name of the constraint.</param>
        /// <param name="nameFormat">The name format.</param>
        /// <param name="names">The names.</param>
        protected virtual void LoadForeignKey(Database schema, Table table, string columnName, string tableName, string tableSchema,
            string referencedColumnName, string referencedTableName, string referencedTableSchema,
            string constraintName,
            NameFormat nameFormat, Names names)
        {
            var foreignKey = BuildForeignKey(names.ColumnsNames[tableName], columnName);
            var reverseForeignKey = BuildForeignKey(names.ColumnsNames[referencedTableName], referencedColumnName);

            var associationName = CreateAssociationName(tableName, tableSchema,
                referencedTableName, referencedTableSchema, constraintName, foreignKey, nameFormat);

            //both parent and child table get an [Association]
            var assoc = new Association();
            assoc.IsForeignKey = true;
            assoc.Name = constraintName;
            assoc.Type = null;
            assoc.ThisKey = foreignKey;
            assoc.OtherKey = reverseForeignKey;
            assoc.Member = associationName.ManyToOneMemberName;
            assoc.CardinalitySpecified = false;
            // TODO: generate assoc.Cardinality?
            table.Type.Associations.Add(assoc);

            //and insert the reverse association:
            var reverseAssociation = new Association();
            reverseAssociation.Name = constraintName;
            reverseAssociation.Type = table.Type.Name;
            reverseAssociation.Member = associationName.OneToManyMemberName;
            reverseAssociation.CardinalitySpecified = false;
            // TODO: generate reverseAssociation.Cardinality?
            reverseAssociation.ThisKey = reverseForeignKey;
            reverseAssociation.OtherKey = foreignKey;
            reverseAssociation.DeleteRule = "NO ACTION";

            string referencedFullDbName = GetFullDbName(referencedTableName, referencedTableSchema);
            var referencedTable = schema.Tables.FirstOrDefault(t => referencedFullDbName == t.Name);
            if (referencedTable == null)
            {
                //try case-insensitive match 
                //reason: MySql's Key_Column_Usage table contains both 'Northwind' and 'northwind'
                referencedTable = schema.Tables.FirstOrDefault(t => referencedFullDbName.ToLower() == t.Name.ToLower());
            }

            if (referencedTable == null)
            {
                ReportForeignKeyError(schema, referencedFullDbName);
            }
            else
            {
                referencedTable.Type.Associations.Add(reverseAssociation);
                assoc.Type = referencedTable.Type.Name;
            }
        }
Beispiel #5
0
        protected override void LoadConstraints(Database schema, DbLinq.Schema.SchemaName schemaName, IDbConnection conn, DbLinq.Schema.NameFormat nameFormat, Names names)
        {
            DbConnection c           = (DbConnection)conn;
            var          foreignKeys = GetForeignKeys(c);

            int iConstName  = foreignKeys.Columns.IndexOf("CONSTRAINT_NAME");
            int iConstType  = foreignKeys.Columns.IndexOf("CONSTRAINT_TYPE");
            int iFromColumn = foreignKeys.Columns.IndexOf("FKEY_FROM_COLUMN");
            int iFromSchema = foreignKeys.Columns.IndexOf("TABLE_SCHEMA");
            int iFromTable  = foreignKeys.Columns.IndexOf("TABLE_NAME");
            int iToColumn   = foreignKeys.Columns.IndexOf("FKEY_TO_COLUMN");
            int iToSchema   = foreignKeys.Columns.IndexOf("FKEY_TO_SCHEMA");
            int iToTable    = foreignKeys.Columns.IndexOf("FKEY_TO_TABLE");

            if (iConstName < 0 || iConstType < 0 ||
                iFromColumn < 0 || iFromSchema < 0 || iFromTable < 0 ||
                iToColumn < 0 || iToSchema < 0 || iToTable < 0)
            {
                WriteErrorLine("Database connection '{0}' doesn't support querying foreign key information.",
                               c.GetType().Name);
                return;
            }

            foreach (DataRow r in foreignKeys.Rows)
            {
                var fromTable  = UnquoteSqlName(GetValue <string>(r, iFromTable, null));
                var fromSchema = UnquoteSqlName(GetValue <string>(r, iFromSchema, null));
                var fromColumn = UnquoteSqlName(GetValue <string>(r, iFromColumn, null));

                string fullFromTable           = GetFullDbName(fromTable, fromSchema);
                DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => fullFromTable == t.Name);
                if (table == null)
                {
                    WriteErrorLine("ERROR L46: Table '" + fromTable + "' not found for column " + fromColumn);
                    continue;
                }

                var constraintType = GetValue <string>(r, iConstType, null);
                var toTable        = UnquoteSqlName(GetValue <string>(r, iToTable, null));

                if (constraintType == "FOREIGN KEY" && toTable != null)
                {
                    var constraintName = GetValue(r, iConstName, (string)null);
                    var toColumn       = UnquoteSqlName(GetValue <string>(r, iToColumn, null));
                    var toSchema       = UnquoteSqlName(GetValue <string>(r, iToSchema, null));
                    LoadForeignKey(schema, table,
                                   fromColumn, fromTable, fromSchema,
                                   toColumn, toTable, toSchema,
                                   constraintName, nameFormat, names);
                }
            }
        }
Beispiel #6
0
        protected override void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)
        {
            var constraints = ReadConstraints(conn, schemaName.DbName);

            foreach (DataConstraint constraint in constraints)
            {
                //find my table:
                string constraintFullDbName    = GetFullDbName(constraint.TableName, constraint.TableSchema);
                DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => constraintFullDbName == t.Name);
                if (table == null)
                {
                    WriteErrorLine("ERROR L100: Table '" + constraint.TableName + "' not found for column " + constraint.ColumnName);
                    continue;
                }

                //if (table.Name.StartsWith("E"))
                //    Logger.Write("---Dbg");

                if (constraint.ConstraintType == "P")
                {
                    //A) add primary key
                    DbLinq.Schema.Dbml.Column pkColumn = table.Type.Columns.Where(c => c.Name == constraint.ColumnName).First();
                    pkColumn.IsPrimaryKey = true;
                }
                else if (constraint.ConstraintType == "R")
                {
                    //if not PRIMARY, it's a foreign key. (constraint_type=="R")
                    //both parent and child table get an [Association]
                    DataConstraint referencedConstraint = constraints.FirstOrDefault(c => c.ConstraintName == constraint.ReverseConstraintName);
                    if (constraint.ReverseConstraintName == null || referencedConstraint == null)
                    {
                        WriteErrorLine("ERROR L127: given R_contraint_name='" + constraint.ReverseConstraintName + "', unable to find parent constraint");
                        continue;
                    }

                    LoadForeignKey(schema, table, constraint.ColumnName, constraint.TableName, constraint.TableSchema,
                                   referencedConstraint.ColumnName, referencedConstraint.TableName,
                                   referencedConstraint.TableSchema,
                                   constraint.ConstraintName, nameFormat, names);
                }
                // custom type, this is a trigger
                else if (constraint.ConstraintType == "T" && constraint.ColumnName != null)
                {
                    var column = table.Type.Columns.Where(c => c.Name == constraint.ColumnName).First();
                    column.Expression    = constraint.Expression;
                    column.IsDbGenerated = true;
                }
            }

            //GuessSequencePopulatedFields(schema);
        }
Beispiel #7
0
        protected override void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)
        {
            //TableSorter.Sort(tables, constraints); //sort tables - parents first

            var foreignKeys = ReadConstraints(conn, schemaName.DbName);

            foreach (DataConstraint keyColRow in foreignKeys)
            {
                //find my table:
                string constraintFullDbName    = GetFullDbName(keyColRow.TableName, keyColRow.TableSchema);
                DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => constraintFullDbName == t.Name);
                if (table == null)
                {
                    WriteErrorLine("ERROR L138: Table '"
                                   + keyColRow.TableName
                                   + "' not found for column "
                                   + keyColRow.ColumnName);
                    continue;
                }

                if (keyColRow.ConstraintType.Equals("P")) //'PRIMARY KEY'
                {
                    //foreach (string pk_name in keyColRow.column_name_primaries)
                    //{
                    DbLinq.Schema.Dbml.Column primaryKeyCol = table.Type.Columns.First(c => c.Name == keyColRow.ColumnName);
                    primaryKeyCol.IsPrimaryKey = true;
                    //}
                    continue;
                }

                if (keyColRow.ConstraintType.Equals("R")) //'FOREIGN KEY'
                {
                    // This is very bad...
                    if (!names.ColumnsNames[keyColRow.ReferencedTableName].ContainsKey(keyColRow.ReferencedColumnName))
                    {
                        continue;
                    }

                    LoadForeignKey(schema, table, keyColRow.ColumnName, keyColRow.TableName,
                                   keyColRow.TableSchema,
                                   keyColRow.ReferencedColumnName, keyColRow.ReferencedTableName,
                                   keyColRow.ReferencedTableSchema,
                                   keyColRow.ConstraintName, nameFormat, names);
                }
            }
        }
Beispiel #8
0
        protected override void LoadConstraints(Database schema, SchemaName schemaName, IDbConnection conn, NameFormat nameFormat, Names names)
        {
            foreach (var table in schema.Table)
            {
                table.Name = table.Name.Split('.').Last();
            }

            var constraints = ReadConstraints(conn, schemaName.DbName);

            //sort tables - parents first (this is moving to SchemaPostprocess)
            //TableSorter.Sort(tables, constraints);

            // Deal with non existing foreign key database
            if (constraints != null)
            {
                foreach (DataConstraint keyColRow in constraints)
                {
                    //find my table:
                    string tableFullDbName         = keyColRow.TableName;// GetFullDbName(keyColRow.TableName, keyColRow.TableSchema);
                    DbLinq.Schema.Dbml.Table table = schema.Tables.FirstOrDefault(t => tableFullDbName == t.Name);
                    if (table == null)
                    {
                        WriteErrorLine("ERROR L46: Table '" + keyColRow.TableName + "' not found for column " + keyColRow.ColumnName);
                        continue;
                    }

                    bool isForeignKey = keyColRow.ConstraintName != "PRIMARY" &&
                                        keyColRow.ReferencedTableName != null;

                    if (isForeignKey)
                    {
                        LoadForeignKey(schema, table, keyColRow.ColumnName, keyColRow.TableName, keyColRow.TableSchema,
                                       keyColRow.ReferencedColumnName, keyColRow.ReferencedTableName,
                                       keyColRow.ReferencedTableSchema,
                                       keyColRow.ConstraintName, nameFormat, names);
                    }
                    else
                    {
                        //A) add primary key
                        DbLinq.Schema.Dbml.Column primaryKeyCol = table.Type.Columns.First(c => c.Name == keyColRow.ColumnName);
                        primaryKeyCol.IsPrimaryKey = true;
                    }
                }
            }
        }
 protected virtual void WriteClassChildren(CodeWriter writer, Table table, Database schema, GenerationContext context)
 {
     var children = GetClassChildren(table).ToList();
     if (children.Count > 0)
     {
         using (writer.WriteRegion("Children"))
         {
             foreach (var child in children)
             {
                 bool hasDuplicates = (from c in children where c.Member == child.Member select c).Count() > 1;
                 WriteClassChild(writer, child, hasDuplicates, schema, context);
             }
         }
     }
 }
 /// <summary>
 /// Returns all parents (ie member referenced as EntityRef)
 /// </summary>
 /// <param name="table"></param>
 /// <returns></returns>
 protected virtual IEnumerable<Association> GetClassParents(Table table)
 {
     return table.Type.Associations.Where(a => a.IsForeignKey);
 }
Beispiel #11
0
        void WriteCustomTypes(CodeTypeDeclaration entity, Table table)
        {
            // detect required custom types
            foreach (var column in table.Type.Columns)
            {
                var extendedType = column.ExtendedType;
                var enumType = extendedType as EnumType;
                if (enumType != null)
                {
                    Context.ExtendedTypes[column] = new GenerationContext.ExtendedTypeAndName {
                        Type = column.ExtendedType,
                        Table = table
                    };
                }
            }

            var customTypesNames = new List<string>();

            // create names and avoid conflits
            foreach (var extendedTypePair in Context.ExtendedTypes)
            {
                if (extendedTypePair.Value.Table != table)
                    continue;

                if (string.IsNullOrEmpty(extendedTypePair.Value.Type.Name))
                {
                    string name = extendedTypePair.Key.Member + "Type";
                    for (; ; )
                    {
                        if ((from t in Context.ExtendedTypes.Values where t.Type.Name == name select t).FirstOrDefault() == null)
                        {
                            extendedTypePair.Value.Type.Name = name;
                            break;
                        }
                        // at 3rd loop, it will look ugly, however we will never go there
                        name = extendedTypePair.Value.Table.Type.Name + name;
                    }
                }
                customTypesNames.Add(extendedTypePair.Value.Type.Name);
            }

            // write custom types
            if (customTypesNames.Count > 0)
            {
                var customTypes = new List<CodeTypeDeclaration>(customTypesNames.Count);

                foreach (var extendedTypePair in Context.ExtendedTypes)
                {
                    if (extendedTypePair.Value.Table != table)
                        continue;

                    var extendedType = extendedTypePair.Value.Type;
                    var enumValue = extendedType as EnumType;

                    if (enumValue != null)
                    {
                        var enumType = new CodeTypeDeclaration(enumValue.Name) {
                            TypeAttributes = TypeAttributes.Public,
                            IsEnum = true,
                        };
                        customTypes.Add(enumType);
                        var orderedValues = from nv in enumValue orderby nv.Value select nv;
                        int currentValue = 1;
                        foreach (var nameValue in orderedValues)
                        {
                            var field = new CodeMemberField() {
                                Name = nameValue.Key,
                            };
                            enumType.Members.Add(field);
                            if (nameValue.Value != currentValue)
                            {
                                currentValue = nameValue.Value;
                                field.InitExpression = new CodePrimitiveExpression(nameValue.Value);
                            }
                            currentValue++;
                        }
                    }
                }

                if (customTypes.Count == 0)
                    return;
                customTypes.First().StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start,
                        string.Format("Custom type definitions for {0}", string.Join(", ", customTypesNames.ToArray()))));
                customTypes.Last().EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, null));
                entity.Members.AddRange(customTypes.ToArray());
            }
        }
Beispiel #12
0
        protected virtual void WriteClassParent(CodeWriter writer, Association parent, bool hasDuplicates, Database schema, GenerationContext context)
        {
            // the following is apparently useless
            DbLinq.Schema.Dbml.Table targetTable = schema.Tables.FirstOrDefault(t => t.Type.Name == parent.Type);
            if (targetTable == null)
            {
                //Logger.Write(Level.Error, "ERROR L191 target table type not found: " + parent.Type + "  (processing " + parent.Name + ")");
                return;
            }

            string member       = parent.Member;
            string storageField = parent.Storage;

            // TODO: remove this
            if (member == parent.ThisKey)
            {
                member       = parent.ThisKey + targetTable.Type.Name; //repeat name to prevent collision (same as Linq)
                storageField = "_x_" + parent.Member;
            }

            writer.WriteField(SpecificationDefinition.Private, storageField,
                              writer.GetGenericName(TypeExtensions.GetShortName(typeof(EntityRef <>)),
                                                    targetTable.Type.Name));

            var storageAttribute = NewAttributeDefinition <AssociationAttribute>();

            storageAttribute["Storage"]      = storageField;
            storageAttribute["OtherKey"]     = parent.OtherKey;
            storageAttribute["ThisKey"]      = parent.ThisKey;
            storageAttribute["Name"]         = parent.Name;
            storageAttribute["IsForeignKey"] = parent.IsForeignKey;

            SpecificationDefinition specifications;

            if (parent.AccessModifierSpecified)
            {
                specifications = GetSpecificationDefinition(parent.AccessModifier);
            }
            else
            {
                specifications = SpecificationDefinition.Public;
            }
            if (parent.ModifierSpecified)
            {
                specifications |= GetSpecificationDefinition(parent.Modifier);
            }

            var propertyName = hasDuplicates
                                   ? member + "_" + string.Join("", parent.TheseKeys.ToArray())
                                   : member;

            using (writer.WriteAttribute(storageAttribute))
                using (writer.WriteAttribute(NewAttributeDefinition <DebuggerNonUserCodeAttribute>()))
                    using (writer.WriteProperty(specifications, propertyName, targetTable.Type.Name))
                    {
                        string storage = writer.GetMemberExpression(storageField, "Entity");
                        using (writer.WritePropertyGet())
                        {
                            writer.WriteLine(writer.GetReturnStatement(storage));
                        }
                        using (writer.WritePropertySet())
                        {
                            // algorithm is:
                            // 1.1. must be different than previous value
                            // 1.2. or HasLoadedOrAssignedValue is false (but why?)
                            // 2. implementations before change
                            // 3. if previous value not null
                            // 3.1. place parent in temp variable
                            // 3.2. set [Storage].Entity to null
                            // 3.3. remove it from parent list
                            // 4. assign value to [Storage].Entity
                            // 5. if value is not null
                            // 5.1. add it to parent list
                            // 5.2. set FK members with entity keys
                            // 6. else
                            // 6.1. set FK members to defaults (null or 0)
                            // 7. implementationas after change

                            //writer.WriteLine(writer.GetStatement(writer.GetAssignmentExpression(storage, writer.GetPropertySetValueExpression())));
                            var entityMember = writer.GetMemberExpression(parent.Storage, "Entity");
                            // 1.1
                            using (writer.WriteIf(writer.GetDifferentExpression(writer.GetPropertySetValueExpression(),
                                                                                entityMember)))
                            {
                                var otherAssociation = schema.GetReverseAssociation(parent);
                                // 2. code before the change
                                // TODO change interface to require a member instead of a column
                                //foreach (IImplementation implementation in context.Implementations())
                                //    implementation.WritePropertyBeforeSet(writer, ???, context);
                                // 3.
                                using (writer.WriteIf(writer.GetDifferentExpression(entityMember, writer.GetNullExpression())))
                                {
                                    var previousEntityRefName = "previous" + parent.Type;
                                    // 3.1.
                                    writer.WriteLine(writer.GetStatement(
                                                         writer.GetVariableDeclarationInitialization(parent.Type, previousEntityRefName, entityMember)
                                                         ));
                                    // 3.2.
                                    writer.WriteLine(writer.GetStatement(
                                                         writer.GetAssignmentExpression(entityMember, writer.GetNullExpression())
                                                         ));
                                    // 3.3.
                                    writer.WriteLine(writer.GetStatement(
                                                         writer.GetMethodCallExpression(
                                                             writer.GetMemberExpression(writer.GetMemberExpression(previousEntityRefName, otherAssociation.Member), "Remove"),
                                                             writer.GetThisExpression())
                                                         ));
                                }
                                // 4.
                                writer.WriteLine(writer.GetStatement(
                                                     writer.GetAssignmentExpression(entityMember, writer.GetPropertySetValueExpression())
                                                     ));

                                // 5. if value is null or not
                                writer.WriteRawIf(writer.GetDifferentExpression(writer.GetPropertySetValueExpression(), writer.GetNullExpression()));
                                // 5.1.
                                writer.WriteLine(writer.GetStatement(
                                                     writer.GetMethodCallExpression(
                                                         writer.GetMemberExpression(writer.GetMemberExpression(writer.GetPropertySetValueExpression(), otherAssociation.Member), "Add"),
                                                         writer.GetThisExpression())
                                                     ));

                                // 5.2
                                var table        = schema.Tables.Single(t => t.Type.Associations.Contains(parent));
                                var childKeys    = parent.TheseKeys.ToArray();
                                var childColumns = (from ck in childKeys select table.Type.Columns.Single(c => c.Member == ck))
                                                   .ToArray();
                                var parentKeys = parent.OtherKeys.ToArray();

                                for (int keyIndex = 0; keyIndex < parentKeys.Length; keyIndex++)
                                {
                                    writer.WriteLine(writer.GetStatement(writer.GetAssignmentExpression(
                                                                             childColumns[keyIndex].Storage ?? childColumns[keyIndex].Member,
                                                                             writer.GetMemberExpression(writer.GetPropertySetValueExpression(), parentKeys[keyIndex])
                                                                             )));
                                }

                                // 6.
                                writer.WriteRawElse();

                                // 6.1.
                                for (int keyIndex = 0; keyIndex < parentKeys.Length; keyIndex++)
                                {
                                    var column            = table.Type.Columns.Single(c => c.Member == childKeys[keyIndex]);
                                    var columnType        = System.Type.GetType(column.Type);
                                    var columnLiteralType = columnType != null?writer.GetLiteralType(columnType) : column.Type;

                                    writer.WriteLine(writer.GetStatement(writer.GetAssignmentExpression(
                                                                             childColumns[keyIndex].Storage ?? childColumns[keyIndex].Member,
                                                                             column.CanBeNull ? writer.GetNullExpression() : writer.GetNullValueExpression(columnLiteralType)
                                                                             )));
                                }

                                writer.WriteRawEndif();

                                // 7. code after change
                                // TODO change interface to require a member instead of a column
                                //foreach (IImplementation implementation in context.Implementations())
                                //    implementation.WritePropertyAfterSet(writer, ???, context);
                            }
                        }
                    }
            writer.WriteLine();
        }
        protected virtual void WriteClassEqualsAndHash(CodeWriter writer, Table table, GenerationContext context)
        {
            List<DbLinq.Schema.Dbml.Column> primaryKeys = table.Type.Columns.Where(c => c.IsPrimaryKey).ToList();
            if (primaryKeys.Count == 0)
            {
                writer.WriteLine("#warning L189 table {0} has no primary key. Multiple C# objects will refer to the same row.",
                                 table.Name);
                return;
            }

            using (writer.WriteRegion(string.Format("GetHashCode(), Equals() - uses column {0} to look up objects in liveObjectMap",
                                                    string.Join(", ", primaryKeys.Select(pk => pk.Member).ToList().ToArray()))))
            {
                // GetHashCode
                using (writer.WriteMethod(SpecificationDefinition.Public | SpecificationDefinition.Override,
                                          "GetHashCode", typeof(int)))
                {
                    string hashCode = null;

                    foreach (var primaryKey in primaryKeys)
                    {
                        var member = writer.GetVariableExpression(primaryKey.Storage);
                        string primaryKeyHashCode = writer.GetMethodCallExpression(writer.GetMemberExpression(member, "GetHashCode"));
                        if (primaryKey.CanBeNull
                        || GetType(primaryKey.Type, false).IsClass) // this patch to ensure that even if DB does not allow nulls,
                        // our in-memory object won't generate a fault
                        {
                            var isNullExpression = writer.GetEqualExpression(member, writer.GetNullExpression());
                            var nullExpression = writer.GetLiteralValue(0);
                            primaryKeyHashCode = "(" + writer.GetTernaryExpression(isNullExpression, nullExpression, primaryKeyHashCode) + ")";
                        }
                        if (string.IsNullOrEmpty(hashCode))
                            hashCode = primaryKeyHashCode;
                        else
                            hashCode = writer.GetXOrExpression(hashCode, primaryKeyHashCode);
                    }
                    writer.WriteLine(writer.GetReturnStatement(hashCode));
                }
                writer.WriteLine();

                // Equals
                string otherAsObject = "o";
                using (writer.WriteMethod(SpecificationDefinition.Public | SpecificationDefinition.Override,
                                          "Equals", typeof(bool), new ParameterDefinition { Type = typeof(object), Name = otherAsObject }))
                {
                    string other = "other";
                    writer.WriteLine(writer.GetStatement(writer.GetAssignmentExpression(
                                                             writer.GetDeclarationExpression(other, table.Type.Name),
                                                             writer.GetCastExpression(otherAsObject, table.Type.Name,
                                                                                      false))));
                    using (writer.WriteIf(writer.GetEqualExpression(other, writer.GetNullExpression())))
                    {
                        writer.WriteLine(writer.GetReturnStatement(writer.GetLiteralValue(false)));
                    }
                    string andExpression = null;
                    foreach (var primaryKey in primaryKeys)
                    {
                        var member = writer.GetVariableExpression(primaryKey.Storage);
                        string primaryKeyTest = writer.GetMethodCallExpression(
                                writer.GetMemberExpression(
                                    writer.GetMemberExpression(
                                        writer.GetGenericName("System.Collections.Generic.EqualityComparer", primaryKey.Type),
                                        "Default"),
                                    "Equals"),
                                member,
                                writer.GetMemberExpression(other, member));
                        if (string.IsNullOrEmpty(andExpression))
                            andExpression = primaryKeyTest;
                        else
                            andExpression = writer.GetAndExpression(andExpression, primaryKeyTest);
                    }
                    writer.WriteLine(writer.GetReturnStatement(andExpression));
                }
            }
        }
 /// <summary>
 /// Writes attach/detach method
 /// </summary>
 /// <param name="writer"></param>
 /// <param name="table"></param>
 /// <param name="schema"></param>
 /// <param name="context"></param>
 protected virtual void WriteClassChildrenAttachment(CodeWriter writer, Table table, Database schema, GenerationContext context)
 {
     var children = GetClassChildren(table).ToList();
     if (children.Count > 0)
     {
         using (writer.WriteRegion("Attachement handlers"))
         {
             foreach (var child in children)
             {
                 // the reverse child is the association seen from the child
                 // we're going to use it...
                 var reverseChild = schema.GetReverseAssociation(child);
                 // ... to get the parent name
                 var memberName = reverseChild.Member;
                 var entityParameter = new ParameterDefinition { Name = "entity", LiteralType = child.Type };
                 // the Attach event handler sets the child entity parent to "this"
                 using (writer.WriteMethod(SpecificationDefinition.Private, GetChildAttachMethodName(child),
                                           null, entityParameter))
                 {
                     writer.WriteLine(
                         writer.GetStatement(
                             writer.GetAssignmentExpression(
                                 writer.GetMemberExpression(entityParameter.Name, memberName),
                                 writer.GetThisExpression())));
                 }
                 writer.WriteLine();
                 // the Detach event handler sets the child entity parent to null
                 using (writer.WriteMethod(SpecificationDefinition.Private, GetChildDetachMethodName(child),
                                           null, entityParameter))
                 {
                     writer.WriteLine(
                         writer.GetStatement(
                             writer.GetAssignmentExpression(
                                 writer.GetMemberExpression(entityParameter.Name, memberName),
                                 writer.GetNullExpression())));
                 }
                 writer.WriteLine();
             }
         }
     }
 }
Beispiel #15
0
        bool ValidateAssociations(Database database, Table table)
        {
            bool error = false;
            foreach (var association in table.Type.Associations)
            {
                var otherType           = database.Tables.Single(t => t.Type.Name == association.Type).Type;
                var otherAssociation    = otherType.Associations.Single(a => a.Type == table.Type.Name && a.ThisKey == association.OtherKey);
                var otherColumn         = otherType.Columns.Single(c => c.Member == association.OtherKey);

                if (association.CardinalitySpecified && association.Cardinality == Cardinality.Many && association.IsForeignKey)
                {
                    error = true;
                    Log.WriteErrorLine("Error DBML1059: The IsForeignKey attribute of the Association element '{0}' of the Type element '{1}' cannnot be '{2}' when the Cardinality attribute is '{3}'.",
                            association.Name, table.Type.Name, association.IsForeignKey, association.Cardinality);
                }
            }
            return error;
        }
Beispiel #16
0
        void GenerateEntityChildrenAttachment(CodeTypeDeclaration entity, Table table, Database schema)
        {
            var children = GetClassChildren(table).ToList();
            if (!children.Any())
                return;

            var havePrimaryKeys = table.Type.Columns.Any(c => c.IsPrimaryKey);

            var handlers = new List<CodeTypeMember>();

            foreach (var child in children)
            {
                // the reverse child is the association seen from the child
                // we're going to use it...
                var reverseChild = schema.GetReverseAssociation(child);
                // ... to get the parent name
                var memberName = reverseChild.Member;

                var sendPropertyChanging = new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(
                            new CodeMethodReferenceExpression(thisReference, "SendPropertyChanging")));

                var attach = new CodeMemberMethod() {
                    Name = child.Member + "_Attach",
                    Parameters = {
                        new CodeParameterDeclarationExpression(child.Type, "entity"),
                    },
                };
                handlers.Add(attach);
                if (havePrimaryKeys)
                    attach.Statements.Add(sendPropertyChanging);
                attach.Statements.Add(
                        new CodeAssignStatement(
                            new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("entity"), memberName),
                            thisReference));

                var detach = new CodeMemberMethod() {
                    Name = child.Member + "_Detach",
                    Parameters = {
                        new CodeParameterDeclarationExpression(child.Type, "entity"),
                    },
                };
                handlers.Add(detach);
                if (havePrimaryKeys)
                    detach.Statements.Add(sendPropertyChanging);
                detach.Statements.Add(
                        new CodeAssignStatement(
                            new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("entity"), memberName),
                            new CodePrimitiveExpression(null)));
            }

            if (handlers.Count == 0)
                return;

            handlers.First().StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Attachment handlers"));
            handlers.Last().EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, null));
            entity.Members.AddRange(handlers.ToArray());
        }
 /// <summary>
 /// Gets the primary keys.
 /// </summary>
 /// <param name="table">The table.</param>
 /// <returns></returns>
 protected static List<string> GetPrimaryKeys(Table table)
 {
     return (from c in table.Type.Columns where c.IsPrimaryKey select c.Name).ToList();
 }
Beispiel #18
0
        void GenerateEntityParents(CodeTypeDeclaration entity, Table table, Database schema)
        {
            var parents = table.Type.Associations.Where(a => a.IsForeignKey);
            if (!parents.Any())
                return;

            var parentMembers = new List<CodeTypeMember>();

            foreach (var parent in parents)
            {
                bool hasDuplicates = (from p in parents where p.Member == parent.Member select p).Count() > 1;
                // WriteClassParent(writer, parent, hasDuplicates, schema, context);
                // the following is apparently useless
                DbLinq.Schema.Dbml.Table targetTable = schema.Tables.FirstOrDefault(t => t.Type.Name == parent.Type);
                if (targetTable == null)
                {
                    //Logger.Write(Level.Error, "ERROR L191 target table type not found: " + parent.Type + "  (processing " + parent.Name + ")");
                    continue;
                }

                string member = parent.Member;
                string storageField = GetStorageFieldName(parent);
                // TODO: remove this
                if (member == parent.ThisKey)
                {
                    member = parent.ThisKey + targetTable.Type.Name; //repeat name to prevent collision (same as Linq)
                    storageField = "_x_" + parent.Member;
                }

                var parentType = new CodeTypeReference(targetTable.Type.Name);
                entity.Members.Add(new CodeMemberField(new CodeTypeReference("EntityRef", parentType), storageField) {
                    InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("EntityRef", parentType)),
                });

                var parentName = hasDuplicates
                    ? member + "_" + string.Join("", parent.TheseKeys.ToArray())
                    : member;
                var property = new CodeMemberProperty() {
                    Name        = parentName,
                    Type        = parentType,
                    Attributes  = ToMemberAttributes(parent),
                    CustomAttributes = {
                        new CodeAttributeDeclaration("Association",
                            new CodeAttributeArgument("Storage", new CodePrimitiveExpression(storageField)),
                            new CodeAttributeArgument("OtherKey", new CodePrimitiveExpression(parent.OtherKey)),
                            new CodeAttributeArgument("ThisKey", new CodePrimitiveExpression(parent.ThisKey)),
                            new CodeAttributeArgument("Name", new CodePrimitiveExpression(parent.Name)),
                            new CodeAttributeArgument("IsForeignKey", new CodePrimitiveExpression(parent.IsForeignKey))),
                        new CodeAttributeDeclaration("DebuggerNonUserCode"),
                    },
                };
                parentMembers.Add(property);
                property.GetStatements.Add(new CodeMethodReturnStatement(
                        new CodePropertyReferenceExpression(
                            new CodeFieldReferenceExpression(thisReference, storageField),
                            "Entity")));

                // algorithm is:
                // 1.1. must be different than previous value
                // 1.2. or HasLoadedOrAssignedValue is false (but why?)
                // 2. implementations before change
                // 3. if previous value not null
                // 3.1. place parent in temp variable
                // 3.2. set [Storage].Entity to null
                // 3.3. remove it from parent list
                // 4. assign value to [Storage].Entity
                // 5. if value is not null
                // 5.1. add it to parent list
                // 5.2. set FK members with entity keys
                // 6. else
                // 6.1. set FK members to defaults (null or 0)
                // 7. implementationas after change
                var otherAssociation = schema.GetReverseAssociation(parent);
                var parentEntity = new CodePropertyReferenceExpression(
                        new CodeFieldReferenceExpression(thisReference, storageField),
                        "Entity");
                var parentTable = schema.Tables.Single(t => t.Type.Associations.Contains(parent));
                var childKeys = parent.TheseKeys.ToArray();
                var childColumns = (from ck in childKeys select table.Type.Columns.Single(c => c.Member == ck))
                                    .ToArray();
                var parentKeys = parent.OtherKeys.ToArray();
                property.SetStatements.Add(new CodeConditionStatement(
                        // 1.1
                        ValuesAreNotEqual_Ref(parentEntity, new CodePropertySetValueReferenceExpression()),
                        // 2. TODO: code before the change
                        // 3. 
                        new CodeConditionStatement(
                            ValueIsNotNull(parentEntity),
                            // 3.1
                            new CodeVariableDeclarationStatement(parentType, "previous" + parent.Type, parentEntity),
                            // 3.2
                            new CodeAssignStatement(parentEntity, new CodePrimitiveExpression(null)),
                            // 3.3
                            new CodeExpressionStatement(
                                 new CodeMethodInvokeExpression(
                                    new CodeMethodReferenceExpression(
                                        new CodePropertyReferenceExpression(
                                            new CodeVariableReferenceExpression("previous" + parent.Type),
                                            otherAssociation.Member),
                                        "Remove"),
                                    thisReference))),
                        // 4.
                        new CodeAssignStatement(parentEntity, new CodePropertySetValueReferenceExpression()),
                        // 5. if value is null or not...
                        new CodeConditionStatement(
                            ValueIsNotNull(new CodePropertySetValueReferenceExpression()),
                            // 5.1
                            new CodeStatement[]{
                                new CodeExpressionStatement(
                                    new CodeMethodInvokeExpression(
                                        new CodeMethodReferenceExpression(
                                            new CodePropertyReferenceExpression(
                                                new CodePropertySetValueReferenceExpression(),
                                                otherAssociation.Member),
                                            "Add"),
                                        thisReference))
                            // 5.2
                            }.Concat(Enumerable.Range(0, parentKeys.Length).Select(i =>
                                (CodeStatement) new CodeAssignStatement(
                                    new CodeVariableReferenceExpression(GetStorageFieldName(childColumns[i])),
                                    new CodePropertyReferenceExpression(
                                        new CodePropertySetValueReferenceExpression(),
                                        parentKeys[i]))
                            )).ToArray(),
                            // 6.
                            Enumerable.Range(0, parentKeys.Length).Select(i => {
                                var column = parentTable.Type.Columns.Single(c => c.Member == childKeys[i]);
                                return (CodeStatement) new CodeAssignStatement(
                                    new CodeVariableReferenceExpression(GetStorageFieldName(childColumns[i])),
                                    column.CanBeNull
                                        ? (CodeExpression) new CodePrimitiveExpression(null)
                                        : (CodeExpression) new CodeDefaultValueExpression(new CodeTypeReference(column.Type)));
                            }).ToArray())
                        // 7: TODO
                ));
            }

            if (parentMembers.Count == 0)
                return;
            parentMembers.First().StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Parents"));
            parentMembers.Last().EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, null));
            entity.Members.AddRange(parentMembers.ToArray());
        }
Beispiel #19
0
        /// <summary>
        /// Loads the columns.
        /// </summary>
        /// <param name="schema">The schema.</param>
        /// <param name="schemaName">Name of the schema.</param>
        /// <param name="conn">The conn.</param>
        /// <param name="nameAliases">The name aliases.</param>
        /// <param name="nameFormat">The name format.</param>
        /// <param name="names">The names.</param>
        protected void LoadColumns(Database schema, SchemaName schemaName, IDbConnection conn, INameAliases nameAliases, NameFormat nameFormat, Names names)
        {
            var columnRows = ReadColumns(conn, schemaName.DbName);

            foreach (var columnRow in columnRows)
            {
                var columnName = CreateColumnName(columnRow.ColumnName, columnRow.TableName, columnRow.TableSchema, nameAliases, nameFormat);
                names.AddColumn(columnRow.TableName, columnName);

                //find which table this column belongs to
                string fullColumnDbName = GetFullDbName(columnRow.TableName, columnRow.TableSchema);
                DbLinq.Schema.Dbml.Table tableSchema = schema.Tables.FirstOrDefault(tblSchema => fullColumnDbName == tblSchema.Name);
                if (tableSchema == null)
                {
                    WriteErrorLine("ERROR L46: Table '" + columnRow.TableName + "' not found for column " + columnRow.ColumnName);
                    continue;
                }
                var column = new Column();
                column.Name   = columnName.DbName;
                column.Member = columnName.PropertyName;
                column.DbType = columnRow.FullType;

                if (columnRow.PrimaryKey.HasValue)
                {
                    column.IsPrimaryKey = columnRow.PrimaryKey.Value;
                }

                bool?generated = (nameAliases != null) ? nameAliases.GetColumnGenerated(columnRow.ColumnName, columnRow.TableName, columnRow.TableSchema) : null;
                if (!generated.HasValue)
                {
                    generated = columnRow.Generated;
                }
                if (generated.HasValue)
                {
                    column.IsDbGenerated = generated.Value;
                }

                AutoSync?autoSync = (nameAliases != null) ? nameAliases.GetColumnAutoSync(columnRow.ColumnName, columnRow.TableName, columnRow.TableSchema) : null;
                if (autoSync.HasValue)
                {
                    column.AutoSync = autoSync.Value;
                }

                // the Expression can originate from two sources:
                // 1. DefaultValue
                // 2. Expression
                // we use any valid source (we can't have both)
                if (column.IsDbGenerated && columnRow.DefaultValue != null)
                {
                    column.Expression = columnRow.DefaultValue;
                }

                column.CanBeNull = columnRow.Nullable;

                string columnTypeAlias = nameAliases != null?nameAliases.GetColumnForcedType(columnRow.ColumnName, columnRow.TableName, columnRow.TableSchema) : null;

                var columnType = MapDbType(columnName.DbName, columnRow);

                var columnEnumType = columnType as EnumType;
                if (columnEnumType != null)
                {
                    var enumType = column.SetExtendedTypeAsEnumType();
                    enumType.Name = columnEnumType.Name;
                    foreach (KeyValuePair <string, int> enumValue in columnEnumType.EnumValues)
                    {
                        enumType[enumValue.Key] = enumValue.Value;
                    }
                }
                else if (columnTypeAlias != null)
                {
                    column.Type = columnTypeAlias;
                }
                else
                {
                    column.Type = columnType.ToString();
                }

                tableSchema.Type.Columns.Add(column);
            }
        }
        protected virtual CodeTypeDeclaration GenerateTableClass(Table table)
        {
            var _class = new CodeTypeDeclaration() { IsClass = true, IsPartial = true, Name = table.Member, TypeAttributes = TypeAttributes.Public };

            _class.CustomAttributes.Add(new CodeAttributeDeclaration("Table", new CodeAttributeArgument("Name", new CodePrimitiveExpression(table.Name))));

            // Implement Constructor
            var constructor = new CodeConstructor() { Attributes = MemberAttributes.Public };
            constructor.Statements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, "OnCreated")));
            _class.Members.Add(constructor);

            // todo: implement INotifyPropertyChanging

            // Implement INotifyPropertyChanged
            _class.BaseTypes.Add(typeof(INotifyPropertyChanged));

            var propertyChangedEvent = new CodeMemberEvent() { Type = new CodeTypeReference(typeof(PropertyChangedEventHandler)), Name = "PropertyChanged", Attributes = MemberAttributes.Public };
            _class.Members.Add(propertyChangedEvent);

            var sendPropertyChangedMethod = new CodeMemberMethod() { Attributes = MemberAttributes.Family, Name = "SendPropertyChanged", Parameters = { new CodeParameterDeclarationExpression(typeof(System.String), "propertyName") } };
            sendPropertyChangedMethod.Statements.Add
                (
                new CodeConditionStatement
                    (
                    new CodeSnippetExpression(propertyChangedEvent.Name + " != null"), // todo: covert this to CodeBinaryOperatorExpression
                    new CodeExpressionStatement
                        (
                        new CodeMethodInvokeExpression
                            (
                            new CodeMethodReferenceExpression(thisReference, propertyChangedEvent.Name),
                            thisReference,
                            new CodeObjectCreateExpression(typeof(PropertyChangedEventArgs), new CodeArgumentReferenceExpression("propertyName"))
                            )
                        )
                    )
                );
            _class.Members.Add(sendPropertyChangedMethod);

            // CodeDom does not currently support partial methods.  This will be a problem for VB.  Will probably be fixed in .net 4
            _class.Members.Add(new CodeSnippetTypeMember("\tpartial void OnCreated();"));

            // todo: add these when the actually get called
            //partial void OnLoaded();
            //partial void OnValidate(System.Data.Linq.ChangeAction action);

            // columns
            foreach (Column column in table.Type.Columns)
            {
                var type = new CodeTypeReference(column.Type);
                var columnMember = column.Member ?? column.Name;

                var field = new CodeMemberField(type, "_" + columnMember);
                _class.Members.Add(field);
                var fieldReference = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), field.Name);

                // CodeDom does not currently support partial methods.  This will be a problem for VB.  Will probably be fixed in .net 4
                string onChangingPartialMethodName = String.Format("On{0}Changing", columnMember);
                _class.Members.Add(new CodeSnippetTypeMember(String.Format("\tpartial void {0}({1} instance);", onChangingPartialMethodName, column.Type)));
                string onChangedPartialMethodName = String.Format("On{0}Changed", columnMember);
                _class.Members.Add(new CodeSnippetTypeMember(String.Format("\tpartial void {0}();", onChangedPartialMethodName)));

                var property = new CodeMemberProperty();
                property.Type = type;
                property.Name = columnMember;
                property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                property.CustomAttributes.Add
                    (
                    new CodeAttributeDeclaration
                        (
                        "Column",
                        new CodeAttributeArgument("Storage", new CodePrimitiveExpression(column.Storage)),
                        new CodeAttributeArgument("Name", new CodePrimitiveExpression(column.Name)),
                        new CodeAttributeArgument("DbType", new CodePrimitiveExpression(column.DbType)),
                        new CodeAttributeArgument("CanBeNull", new CodePrimitiveExpression(column.CanBeNull)),
                        new CodeAttributeArgument("IsPrimaryKey", new CodePrimitiveExpression(column.IsPrimaryKey))
                        )
                    );
                property.CustomAttributes.Add(new CodeAttributeDeclaration("DebuggerNonUserCode"));
                property.GetStatements.Add(new CodeMethodReturnStatement(fieldReference));
                property.SetStatements.Add
                    (
                    new CodeConditionStatement
                        (
                        new CodeSnippetExpression(field.Name + " != value"), // todo: covert this to CodeBinaryOperatorExpression
                        new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, onChangingPartialMethodName, new CodePropertySetValueReferenceExpression())),
                        new CodeAssignStatement(fieldReference, new CodePropertySetValueReferenceExpression()),
                        new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, sendPropertyChangedMethod.Name, new CodePrimitiveExpression(property.Name))),
                        new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, onChangedPartialMethodName))
                        )
                    );
                _class.Members.Add(property);
            }

            // TODO: implement associations

            // TODO: implement functions / procedures

            // TODO: Override Equals and GetHashCode

            return _class;
        }
Beispiel #21
0
 void GenerateExtensibilityDeclarations(CodeTypeDeclaration entity, Table table)
 {
     var partialMethods = new[] { CreatePartialMethod("OnCreated") }
         .Concat(table.Type.Columns.Select(c => new[] { CreateChangedMethodDecl(c), CreateChangingMethodDecl(c) })
             .SelectMany(md => md)).ToArray();
     partialMethods.First().StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Extensibility Method Declarations"));
     partialMethods.Last().EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, null));
     entity.Members.AddRange(partialMethods);
 }
 protected virtual void WriteClassParents(CodeWriter writer, Table table, Database schema, GenerationContext context)
 {
     var parents = GetClassParents(table).ToList();
     if (parents.Count > 0)
     {
         using (writer.WriteRegion("Parents"))
         {
             foreach (var parent in parents)
             {
                 bool hasDuplicates = (from p in parents where p.Member == parent.Member select p).Count() > 1;
                 WriteClassParent(writer, parent, hasDuplicates, schema, context);
             }
         }
     }
 }
Beispiel #23
0
 IEnumerable<Association> GetClassChildren(Table table)
 {
     return table.Type.Associations.Where(a => !a.IsForeignKey);
 }
Beispiel #24
0
        void GenerateEntityGetHashCodeAndEquals(CodeTypeDeclaration entity, Table table)
        {
            var primaryKeys = table.Type.Columns.Where(c => c.IsPrimaryKey);
            var pkCount = primaryKeys.Count();
            if (pkCount == 0)
            {
                Warning("Table {0} has no primary key(s).  Skipping /generate-equals-hash for this table.",
                        table.Name);
                return;
            }
            entity.BaseTypes.Add(new CodeTypeReference(typeof(IEquatable<>)) {
                TypeArguments = { new CodeTypeReference(entity.Name) },
            });

            var method = new CodeMemberMethod() {
                Attributes  = MemberAttributes.Public | MemberAttributes.Override,
                Name        = "GetHashCode",
                ReturnType  = new CodeTypeReference(typeof(int)),
            };
            entity.Members.Add(method);
            method.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "hc", new CodePrimitiveExpression(0)));
            var numShifts = 32 / pkCount;
            int pki = 0;
            foreach (var pk in primaryKeys)
            {
                var shift = 1 << (pki++ * numShifts);
                // lack of exclusive-or means we instead split the 32-bit hash code value
                // into pkCount "chunks", each chunk being numShifts in size.
                // Thus, if there are two primary keys, the first primary key gets the
                // lower 16 bits, while the second primray key gets the upper 16 bits.
                CodeStatement update = new CodeAssignStatement(
                        new CodeVariableReferenceExpression("hc"),
                        new CodeBinaryOperatorExpression(
                            new CodeVariableReferenceExpression("hc"),
                            CodeBinaryOperatorType.BitwiseOr,
                            new CodeBinaryOperatorExpression(
                                new CodeMethodInvokeExpression(
                                    new CodeMethodReferenceExpression(
                                        new CodeVariableReferenceExpression(GetStorageFieldName(pk)),
                                        "GetHashCode")),
                                CodeBinaryOperatorType.Multiply,
                                new CodePrimitiveExpression(shift))));
                var pkType = System.Type.GetType(pk.Type);
                if (pk.CanBeNull || (pkType != null && (pkType.IsClass || pkType.IsNullable())))
                {
                    update = new CodeConditionStatement(
                            ValueIsNotNull(new CodeVariableReferenceExpression(GetStorageFieldName(pk))),
                            update);
                }
                method.Statements.Add(update);
            }
            method.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("hc")));

            method = new CodeMemberMethod() {
                Attributes  = MemberAttributes.Public | MemberAttributes.Override,
                Name        = "Equals",
                ReturnType  = new CodeTypeReference(typeof(bool)),
                Parameters = {
                    new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(object)), "value"),
                },
            };
            entity.Members.Add(method);
            method.Statements.Add(
                    new CodeConditionStatement(
                        ValueIsNull(new CodeVariableReferenceExpression("value")), 
                        new CodeMethodReturnStatement(new CodePrimitiveExpression(false))));
            method.Statements.Add(
                    new CodeConditionStatement(
                        ValuesAreNotEqual_Ref(
                            new CodeMethodInvokeExpression(
                                new CodeMethodReferenceExpression(
                                    new CodeVariableReferenceExpression("value"),
                                    "GetType")),
                            new CodeMethodInvokeExpression(
                                new CodeMethodReferenceExpression(thisReference, "GetType"))),
                        new CodeMethodReturnStatement(new CodePrimitiveExpression(false))));
            method.Statements.Add(
                    new CodeVariableDeclarationStatement(
                        new CodeTypeReference(entity.Name),
                        "other",
                        new CodeCastExpression(new CodeTypeReference(entity.Name), new CodeVariableReferenceExpression("value"))));
            method.Statements.Add(
                    new CodeMethodReturnStatement(
                        new CodeMethodInvokeExpression(
                            new CodeMethodReferenceExpression(thisReference, "Equals"),
                            new CodeVariableReferenceExpression("other"))));

            method = new CodeMemberMethod() {
                Attributes  = MemberAttributes.Public,
                Name        = "Equals",
                ReturnType  = new CodeTypeReference(typeof(bool)),
                Parameters  = {
                    new CodeParameterDeclarationExpression(new CodeTypeReference(entity.Name), "value"),
                },
                ImplementationTypes = {
                    new CodeTypeReference("IEquatable", new CodeTypeReference(entity.Name)),
                },
            };
            entity.Members.Add(method);
            method.Statements.Add(
                    new CodeConditionStatement(
                        ValueIsNull(new CodeVariableReferenceExpression("value")),
                        new CodeMethodReturnStatement(new CodePrimitiveExpression(false))));

            CodeExpression equals = null;
            foreach (var pk in primaryKeys)
            {
                var compare = new CodeMethodInvokeExpression(
                        new CodeMethodReferenceExpression(
                            new CodePropertyReferenceExpression(
                                new CodeTypeReferenceExpression(
                                    new CodeTypeReference("System.Collections.Generic.EqualityComparer",
                                        new CodeTypeReference(pk.Type))),
                                "Default"),
                            "Equals"),
                        new CodeFieldReferenceExpression(thisReference, GetStorageFieldName(pk)),
                        new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("value"), GetStorageFieldName(pk)));
                equals = equals == null
                    ? (CodeExpression) compare
                    : (CodeExpression) new CodeBinaryOperatorExpression(
                        equals,
                        CodeBinaryOperatorType.BooleanAnd,
                        compare);
            }
            method.Statements.Add(
                    new CodeMethodReturnStatement(equals));
        }
 /// <summary>
 /// Writes class ctor.
 /// EntitySet initializations
 /// </summary>
 /// <param name="writer"></param>
 /// <param name="table"></param>
 /// <param name="schema"></param>
 /// <param name="context"></param>
 protected virtual void WriteClassCtor(CodeWriter writer, Table table, Database schema, GenerationContext context)
 {
     using (writer.WriteRegion("ctor"))
     using (writer.WriteCtor(SpecificationDefinition.Public, table.Type.Name, new ParameterDefinition[0], null))
     {
         // children are EntitySet
         foreach (var child in GetClassChildren(table))
         {
             // if the association has a storage, we use it. Otherwise, we use the property name
             var entitySetMember = child.Storage ?? child.Member;
             writer.WriteLine(writer.GetStatement(
                 writer.GetAssignmentExpression(
                     entitySetMember,
                     writer.GetNewExpression(writer.GetMethodCallExpression(
                         writer.GetGenericName(TypeExtensions.GetShortName(typeof(EntitySet<>)), child.Type),
                         GetChildAttachMethodName(child),
                         GetChildDetachMethodName(child)
                     ))
                 )
                 ));
         }
         // the parents are the entities referenced by a FK. So a "parent" is an EntityRef
         foreach (var parent in GetClassParents(table))
         {
             var entityRefMember = parent.Storage;
             writer.WriteLine(writer.GetStatement(
                 writer.GetAssignmentExpression(
                     entityRefMember,
                     writer.GetNewExpression(writer.GetMethodCallExpression(
                     writer.GetGenericName(TypeExtensions.GetShortName(typeof(EntityRef<>)), parent.Type)
                     ))
                 )
             ));
         }
         writer.WriteLine(writer.GetStatement(writer.GetMethodCallExpression("OnCreated")));
     }
 }
 /// <summary>
 /// Class headers are written at top of class
 /// They consist in specific headers writen by interface implementors
 /// </summary>
 /// <param name="writer"></param>
 /// <param name="table"></param>
 /// <param name="context"></param>
 private void WriteClassHeader(CodeWriter writer, Table table, GenerationContext context)
 {
     foreach (IImplementation implementation in context.Implementations())
         implementation.WriteClassHeader(writer, table, context);
 }
Beispiel #27
0
        void GenerateEntityChildren(CodeTypeDeclaration entity, Table table, Database schema)
        {
            var children = GetClassChildren(table);
            if (children.Any())
            {
                var childMembers = new List<CodeTypeMember>();

                foreach (var child in children)
                {
                    bool hasDuplicates = (from c in children where c.Member == child.Member select c).Count() > 1;

                    // the following is apparently useless
                    var targetTable = schema.Tables.FirstOrDefault(t => t.Type.Name == child.Type);
                    if (targetTable == null)
                    {
                        //Logger.Write(Level.Error, "ERROR L143 target table class not found:" + child.Type);
                        continue;
                    }

                    var childType = new CodeTypeReference("EntitySet", new CodeTypeReference(child.Type));
                    var storage = GetStorageFieldName(child);
                    entity.Members.Add(new CodeMemberField(childType, storage));

                    var childName = hasDuplicates
                        ? child.Member + "_" + string.Join("", child.OtherKeys.ToArray())
                        : child.Member;
                    var property = new CodeMemberProperty() {
                        Name        = childName,
                        Type        = childType,
                        Attributes  = ToMemberAttributes(child),
                        CustomAttributes = {
                            new CodeAttributeDeclaration("Association",
                                new CodeAttributeArgument("Storage", new CodePrimitiveExpression(GetStorageFieldName(child))),
                                new CodeAttributeArgument("OtherKey", new CodePrimitiveExpression(child.OtherKey)),
                                new CodeAttributeArgument("ThisKey", new CodePrimitiveExpression(child.ThisKey)),
                                new CodeAttributeArgument("Name", new CodePrimitiveExpression(child.Name))),
                            new CodeAttributeDeclaration("DebuggerNonUserCode"),
                        },
                    };
                    childMembers.Add(property);
                    property.GetStatements.Add(new CodeMethodReturnStatement(
                            new CodeFieldReferenceExpression(thisReference, storage)));
                    property.SetStatements.Add(new CodeAssignStatement(
                            new CodeFieldReferenceExpression(thisReference, storage),
                            new CodePropertySetValueReferenceExpression()));
                }

                if (childMembers.Count == 0)
                    return;
                childMembers.First().StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Children"));
                childMembers.Last().EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, null));
                entity.Members.AddRange(childMembers.ToArray());
            }
        }
 protected virtual void WriteClassExtensibilityDeclarations(CodeWriter writer, Table table, GenerationContext context)
 {
     using (writer.WriteRegion("Extensibility Method Definitions"))
     {
         writer.WriteLine("partial void OnCreated();");
         foreach (var c in table.Type.Columns)
         {
             writer.WriteLine("partial void On{0}Changed();", c.Member);
             writer.WriteLine("partial void On{0}Changing({1} value);", c.Member, GetTypeOrExtendedType(writer, c));
         }
     }
 }
Beispiel #29
0
        private void WriteClassChild(CodeWriter writer, Association child, bool hasDuplicates, Database schema, GenerationContext context)
        {
            // the following is apparently useless
            DbLinq.Schema.Dbml.Table targetTable = schema.Tables.FirstOrDefault(t => t.Type.Name == child.Type);
            if (targetTable == null)
            {
                //Logger.Write(Level.Error, "ERROR L143 target table class not found:" + child.Type);
                return;
            }

            var storageAttribute = NewAttributeDefinition <AssociationAttribute>();

            storageAttribute["Storage"]  = child.Storage;
            storageAttribute["OtherKey"] = child.OtherKey;
            storageAttribute["ThisKey"]  = child.ThisKey;
            storageAttribute["Name"]     = child.Name;

            SpecificationDefinition specifications;

            if (child.AccessModifierSpecified)
            {
                specifications = GetSpecificationDefinition(child.AccessModifier);
            }
            else
            {
                specifications = SpecificationDefinition.Public;
            }
            if (child.ModifierSpecified)
            {
                specifications |= GetSpecificationDefinition(child.Modifier);
            }

            var propertyName = hasDuplicates
                                   ? child.Member + "_" + string.Join("", child.OtherKeys.ToArray())
                                   : child.Member;

            var propertyType = writer.GetGenericName(TypeExtensions.GetShortName(typeof(EntitySet <>)), child.Type);

            if (child.Storage != null)
            {
                writer.WriteField(SpecificationDefinition.Private, child.Storage, propertyType);
            }

            using (writer.WriteAttribute(storageAttribute))
                using (writer.WriteAttribute(NewAttributeDefinition <DebuggerNonUserCodeAttribute>()))
                    using (writer.WriteProperty(specifications, propertyName,
                                                writer.GetGenericName(TypeExtensions.GetShortName(typeof(EntitySet <>)), child.Type)))
                    {
                        // if we have a backing field, use it
                        if (child.Storage != null)
                        {
                            // the getter returns the field
                            using (writer.WritePropertyGet())
                            {
                                writer.WriteLine(writer.GetReturnStatement(
                                                     child.Storage
                                                     ));
                            }
                            // the setter assigns the field
                            using (writer.WritePropertySet())
                            {
                                writer.WriteLine(writer.GetStatement(
                                                     writer.GetAssignmentExpression(
                                                         child.Storage,
                                                         writer.GetPropertySetValueExpression())
                                                     ));
                            }
                        }
                        // otherwise, use automatic property
                        else
                        {
                            writer.WriteAutomaticPropertyGetSet();
                        }
                    }
            writer.WriteLine();
        }
 /// <summary>
 /// Writes all properties, depending on the use (simple property or FK)
 /// </summary>
 /// <param name="writer"></param>
 /// <param name="table"></param>
 /// <param name="context"></param>
 protected virtual void WriteClassProperties(CodeWriter writer, Table table, GenerationContext context)
 {
     foreach (var property in table.Type.Columns)
     {
         var property1 = property;
         var relatedAssociations = from a in table.Type.Associations
                                   where a.IsForeignKey
                                   && a.TheseKeys.Contains(property1.Name)
                                   select a;
         WriteClassProperty(writer, property, relatedAssociations, context);
     }
 }
        /// <summary>
        /// Loads the tables in the given schema.
        /// </summary>
        /// <param name="schema">The schema.</param>
        /// <param name="schemaName">Name of the schema.</param>
        /// <param name="conn">The conn.</param>
        /// <param name="nameAliases">The name aliases.</param>
        /// <param name="nameFormat">The name format.</param>
        /// <param name="names">The names.</param>
        protected virtual void LoadTables(Database schema, SchemaName schemaName, IDbConnection conn, INameAliases nameAliases, NameFormat nameFormat, Names names)
        {
            var tables = ReadTables(conn, schemaName.DbName);
            foreach (var row in tables)
            {
                var tableName = CreateTableName(row.Name, row.Schema, nameAliases, nameFormat);
                names.TablesNames[tableName.DbName] = tableName;

                var table = new Table();
                table.Name = tableName.DbName;
                table.Member = tableName.MemberName;
                table.Type.Name = tableName.ClassName;
                schema.Tables.Add(table);
            }
        }
Beispiel #32
0
        protected CodeTypeDeclaration GenerateTableClass(Table table, Database database)
        {
            var _class = new CodeTypeDeclaration() {
                IsClass         = true, 
                IsPartial       = true, 
                Name            = table.Type.Name, 
                TypeAttributes  = TypeAttributes.Public,
                CustomAttributes = {
                    new CodeAttributeDeclaration("Table", 
                        new CodeAttributeArgument("Name", new CodePrimitiveExpression(table.Name))),
                },
            };

            WriteCustomTypes(_class, table);

            var havePrimaryKeys = table.Type.Columns.Any(c => c.IsPrimaryKey);
            if (havePrimaryKeys)
            {
                GenerateINotifyPropertyChanging(_class);
                GenerateINotifyPropertyChanged(_class);
            }

            // Implement Constructor
            var constructor = new CodeConstructor() { Attributes = MemberAttributes.Public };
            // children are EntitySet
            foreach (var child in GetClassChildren(table))
            {
                // if the association has a storage, we use it. Otherwise, we use the property name
                var entitySetMember = GetStorageFieldName(child);
                constructor.Statements.Add(
                    new CodeAssignStatement(
                        new CodeVariableReferenceExpression(entitySetMember),
                        new CodeObjectCreateExpression(
                            new CodeTypeReference("EntitySet", new CodeTypeReference(child.Type)),
                            new CodeDelegateCreateExpression(
                                new CodeTypeReference("Action", new CodeTypeReference(child.Type)),
                                thisReference, child.Member + "_Attach"),
                            new CodeDelegateCreateExpression(
                                new CodeTypeReference("Action", new CodeTypeReference(child.Type)),
                                thisReference, child.Member + "_Detach"))));
            }
            constructor.Statements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, "OnCreated")));
            _class.Members.Add(constructor);

            if (Context.Parameters.GenerateEqualsHash)
            {
                GenerateEntityGetHashCodeAndEquals(_class, table);
            }

            GenerateExtensibilityDeclarations(_class, table);

            // todo: add these when the actually get called
            //partial void OnLoaded();
            //partial void OnValidate(System.Data.Linq.ChangeAction action);

            // columns
            foreach (Column column in table.Type.Columns)
            {
                var relatedAssociations = from a in table.Type.Associations
                                          where a.IsForeignKey && a.TheseKeys.Contains(column.Name)
                                          select a;

                var type = ToCodeTypeReference(column);
                var columnMember = column.Member ?? column.Name;

                var field = new CodeMemberField(type, GetStorageFieldName(column));
                _class.Members.Add(field);
                var fieldReference = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), field.Name);

                var onChanging  = GetChangingMethodName(columnMember);
                var onChanged   = GetChangedMethodName(columnMember);

                var property = new CodeMemberProperty();
                property.Type = type;
                property.Name = columnMember;
                property.Attributes = MemberAttributes.Public | MemberAttributes.Final;

                var defAttrValues = new ColumnAttribute();
                var args = new List<CodeAttributeArgument>() {
                    new CodeAttributeArgument("Storage", new CodePrimitiveExpression(GetStorageFieldName(column))),
                    new CodeAttributeArgument("Name", new CodePrimitiveExpression(column.Name)),
                    new CodeAttributeArgument("DbType", new CodePrimitiveExpression(column.DbType)),
                };
                if (defAttrValues.IsPrimaryKey != column.IsPrimaryKey)
                    args.Add(new CodeAttributeArgument("IsPrimaryKey", new CodePrimitiveExpression(column.IsPrimaryKey)));
                if (defAttrValues.IsDbGenerated != column.IsDbGenerated)
                    args.Add(new CodeAttributeArgument("IsDbGenerated", new CodePrimitiveExpression(column.IsDbGenerated)));
                if (column.AutoSync != DbLinq.Schema.Dbml.AutoSync.Default)
                    args.Add(new CodeAttributeArgument("AutoSync", 
                        new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("AutoSync"), column.AutoSync.ToString())));
                if (defAttrValues.CanBeNull != column.CanBeNull)
                    args.Add(new CodeAttributeArgument("CanBeNull", new CodePrimitiveExpression(column.CanBeNull)));
                if (column.Expression != null)
                    args.Add(new CodeAttributeArgument("Expression", new CodePrimitiveExpression(column.Expression)));
                property.CustomAttributes.Add(
                    new CodeAttributeDeclaration("Column", args.ToArray()));
                property.CustomAttributes.Add(new CodeAttributeDeclaration("DebuggerNonUserCode"));

                property.GetStatements.Add(new CodeMethodReturnStatement(fieldReference));

                var whenUpdating = new List<CodeStatement>(
                    from assoc in relatedAssociations
                    select (CodeStatement) new CodeConditionStatement(
                        new CodePropertyReferenceExpression(
                            new CodeVariableReferenceExpression(GetStorageFieldName(assoc)),
                            "HasLoadedOrAssignedValue"),
                        new CodeThrowExceptionStatement(
                            new CodeObjectCreateExpression(typeof(System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException)))));
                whenUpdating.Add(
                        new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, onChanging, new CodePropertySetValueReferenceExpression())));
                if (havePrimaryKeys)
                    whenUpdating.Add(
                            new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, "SendPropertyChanging")));
                whenUpdating.Add(
                        new CodeAssignStatement(fieldReference, new CodePropertySetValueReferenceExpression()));
                if (havePrimaryKeys)
                    whenUpdating.Add(
                            new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, "SendPropertyChanged", new CodePrimitiveExpression(property.Name))));
                whenUpdating.Add(
                        new CodeExpressionStatement(new CodeMethodInvokeExpression(thisReference, onChanged)));

                var fieldType = TypeLoader.Load(column.Type);
                // This is needed for VB.NET generation; 
                // int/string/etc. can use '<>' for comparison, but NOT arrays and other reference types.
                // arrays/etc. require the 'Is' operator, which is CodeBinaryOperatorType.IdentityEquality.
                // The VB IsNot operator is not exposed from CodeDom.
                // Thus, we need to special-case: if fieldType is a ref or nullable type,
                //  generate '(field Is value) = false'; otherwise, 
                //  generate '(field <> value)'
                CodeBinaryOperatorExpression condition = fieldType.IsClass || fieldType.IsNullable()
                    ? ValuesAreNotEqual_Ref(new CodeVariableReferenceExpression(field.Name), new CodePropertySetValueReferenceExpression())
                    : ValuesAreNotEqual(new CodeVariableReferenceExpression(field.Name), new CodePropertySetValueReferenceExpression());
                property.SetStatements.Add(new CodeConditionStatement(condition, whenUpdating.ToArray()));
                _class.Members.Add(property);
            }

            GenerateEntityChildren(_class, table, database);
            GenerateEntityChildrenAttachment(_class, table, database);
            GenerateEntityParents(_class, table, database);

            return _class;
        }