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); } } }
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); }
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); } } }
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; } } } }
/// <summary> /// Writes property setter, for FK properties /// </summary> /// <param name="writer"></param> /// <param name="property"></param> /// <param name="relatedAssociations"></param> /// <param name="context"></param> private void WriteClassPropertyAccessorSet(CodeWriter writer, Column property, IEnumerable<Association> relatedAssociations, GenerationContext context) { // if new value if different from old one using (writer.WriteIf(writer.GetDifferentExpression(writer.GetPropertySetValueExpression(), writer.GetVariableExpression(property.Storage)))) { // if the property is used as a FK, we ensure that it hasn't been already loaded or assigned foreach (var relatedAssociation in relatedAssociations) { // first thing to check: ensure the association backend isn't already affected. // if it is the case, then the property must not be manually set // R# considers the following as an error, but the csc doesn't //var memberName = ReflectionUtility.GetMemberInfo<DbLinq.Data.Linq.EntityRef<object>>(e => e.HasLoadedOrAssignedValue).Name; var memberName = "HasLoadedOrAssignedValue"; using (writer.WriteIf(writer.GetMemberExpression(relatedAssociation.Storage, memberName))) { writer.WriteLine(writer.GetThrowStatement(writer.GetNewExpression( writer.GetMethodCallExpression( writer.GetLiteralFullType( typeof( System.Data.Linq. ForeignKeyReferenceAlreadyHasValueException ))) ))); } } // the before and after are used by extensions related to interfaces // for example INotifyPropertyChanged // here the code before the change foreach (IImplementation implementation in context.Implementations()) implementation.WritePropertyBeforeSet(writer, property, context); // property assignment writer.WriteLine( writer.GetStatement( writer.GetAssignmentExpression(writer.GetVariableExpression(property.Storage), writer.GetPropertySetValueExpression()))); // here the code after change foreach (IImplementation implementation in context.Implementations()) implementation.WritePropertyAfterSet(writer, property, context); } }
/// <summary> /// Writes property accessor /// </summary> /// <param name="writer"></param> /// <param name="property"></param> /// <param name="relatedAssociations"></param> /// <param name="context"></param> protected virtual void WriteClassPropertyAccessors(CodeWriter writer, Column property, IEnumerable<Association> relatedAssociations, GenerationContext context) { //generate [Column(...)] attribute var column = NewAttributeDefinition<ColumnAttribute>(); column["Storage"] = property.Storage; column["Name"] = property.Name; column["DbType"] = property.DbType; // be smart: we only write attributes when they differ from the default values var columnAttribute = new ColumnAttribute(); if (property.IsPrimaryKey != columnAttribute.IsPrimaryKey) column["IsPrimaryKey"] = property.IsPrimaryKey; if (property.IsDbGenerated != columnAttribute.IsDbGenerated) column["IsDbGenerated"] = property.IsDbGenerated; if (property.AutoSync != DbLinq.Schema.Dbml.AutoSync.Default) column["AutoSync"] = new EnumFullname("AutoSync", property.AutoSync); if (property.CanBeNull != columnAttribute.CanBeNull) column["CanBeNull"] = property.CanBeNull; if (property.Expression != null) column["Expression"] = property.Expression; var specifications = property.AccessModifierSpecified ? GetSpecificationDefinition(property.AccessModifier) : SpecificationDefinition.Public; if (property.ModifierSpecified) specifications |= GetSpecificationDefinition(property.Modifier); //using (WriteAttributes(writer, context.Parameters.MemberExposedAttributes)) using (WriteAttributes(writer, GetAttributeNames(context, context.Parameters.MemberAttributes))) using (writer.WriteAttribute(NewAttributeDefinition<DebuggerNonUserCodeAttribute>())) using (writer.WriteAttribute(column)) using (writer.WriteProperty(specifications, property.Member, GetTypeOrExtendedType(writer, property))) { // on auto storage, we're just lazy if (property.Storage == null) writer.WriteAutomaticPropertyGetSet(); else { using (writer.WritePropertyGet()) { writer.WriteLine(writer.GetReturnStatement(writer.GetVariableExpression(property.Storage))); } using (writer.WritePropertySet()) { WriteClassPropertyAccessorSet(writer, property, relatedAssociations, context); } } } }
protected virtual void WriteClassPropertyBackingField(CodeWriter writer, Column property, GenerationContext context) { //AttributeDefinition autoGenAttribute = null; //if (property.IsDbGenerated) // autoGenAttribute = NewAttributeDefinition<AutoGenIdAttribute>(); //using (writer.WriteAttribute(autoGenAttribute)) // for auto-properties, we just won't generate a private field if (property.Storage != null) writer.WriteField(SpecificationDefinition.Private, property.Storage, GetTypeOrExtendedType(writer, property)); }
/// <summary> /// Writes class property /// </summary> /// <param name="writer"></param> /// <param name="property"></param> /// <param name="relatedAssociations">non null if property is a FK</param> /// <param name="context"></param> protected virtual void WriteClassProperty(CodeWriter writer, Column property, IEnumerable<Association> relatedAssociations, GenerationContext context) { using (writer.WriteRegion(string.Format("{0} {1}", GetTypeOrExtendedType(writer, property), property.Member))) { WriteClassPropertyBackingField(writer, property, context); WriteClassPropertyAccessors(writer, property, relatedAssociations, context); } }
protected virtual string GetTypeOrExtendedType(CodeWriter writer, Column property) { object extendedType = property.ExtendedType; var enumType = extendedType as EnumType; if (enumType != null) return writer.GetEnumType(enumType.Name); return writer.GetLiteralType(GetType(property.Type, property.CanBeNull)); }
/// <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); } }
static string GetStorageFieldName(Column column) { return GetStorageFieldName(column.Storage ?? column.Member); }
static CodeTypeReference ToCodeTypeReference(Column column) { var t = System.Type.GetType(column.Type); if (t == null) return new CodeTypeReference(column.Type); return t.IsValueType && column.CanBeNull ? new CodeTypeReference("System.Nullable", new CodeTypeReference(column.Type)) : new CodeTypeReference(column.Type); }
CodeTypeMember CreateChangingMethodDecl(Column column) { return CreatePartialMethod(GetChangingMethodName(column.Member), new CodeParameterDeclarationExpression(ToCodeTypeReference(column), "value")); }
CodeTypeMember CreateChangedMethodDecl(Column column) { return CreatePartialMethod(GetChangedMethodName(column.Member)); }