public void DoNewValueTypePropertyNotNullable(ObjectClass objClass, ValueTypeProperty prop, string prefix) { if (!PreMigration(PropertyMigrationEventType.Add, null, prop)) return; var tblName = objClass.GetTableRef(db); var colName = Construct.ColumnName(prop, prefix); var dbType = prop.GetDbType(); var size = prop.GetSize(); var scale = prop.GetScale(); var def = SchemaManager.GetDefaultConstraint(prop); var isSimplyCheckable = objClass.GetTableMapping() == TableMapping.TPT || objClass.BaseObjectClass == null; bool updateDone = false; // classes that do have this property var classes = objClass.AndChildren(c => c.SubClasses).Select(cls => Construct.DiscriminatorValue(cls)).ToList(); Log.InfoFormat("New not nullable ValueType Property: [{0}.{1}] (col:{2})", prop.ObjectClass.Name, prop.Name, colName); CheckValueTypePropertyHasWarnings(prop); if (db.CheckTableContainsData(tblName, isSimplyCheckable ? null : classes)) { db.CreateColumn(tblName, colName, dbType, size, scale, true, isSimplyCheckable ? def : null); updateDone = WriteDefaultValue(tblName, colName, def, isSimplyCheckable ? null : classes); } else { db.CreateColumn(tblName, colName, dbType, size, scale, !isSimplyCheckable, isSimplyCheckable ? def : null); updateDone = true; } if (updateDone && isSimplyCheckable) { db.AlterColumn(tblName, colName, dbType, size, scale, false, def); } else if (updateDone && !isSimplyCheckable) { CreateTPHNotNullCheckConstraint(tblName, colName, objClass); } else if (!updateDone && isSimplyCheckable) { Log.ErrorFormat("unable to set ValueType Property '{0}' to NOT NULL when table '{1}' contains data: No supported default constraint found", colName, tblName); } else if (!updateDone && !isSimplyCheckable) { Log.ErrorFormat("unable to create CHECK constraint on ValueType Property '{0}' when table '{1}' contains data: No supported default constraint found", colName, tblName); } PostMigration(PropertyMigrationEventType.Add, null, prop); }
internal void CreateTPHNotNullCheckConstraint(TableRef tblName, string colName, ObjectClass objClass) { // classes that do have this property var classes = objClass.AndChildren(c => c.SubClasses).Select(cls => Construct.DiscriminatorValue(cls)).ToList(); // classes that do not have this property var otherClasses = objClass .BaseObjectClass // step once up, which is allowed, since we're not base (else isSimplyCheckable would be true) and necessary to let the skip work (see below) .AndParents(cls => cls.BaseObjectClass) .SelectMany(cls => cls .AndChildren(c => c.SubClasses .Where(child => child != objClass))) // skip self (and thus its children) .Select(cls => Construct.DiscriminatorValue(cls)).ToList(); var checkExpressions = new Dictionary<List<string>, Expression<Func<string, bool>>>() { { classes, s => s != null }, { otherClasses, s => s == null }, }; var checkConstraintName = Construct.CheckConstraintName(tblName.Name, colName); if (db.CheckCheckConstraintPossible(tblName, colName, checkConstraintName, checkExpressions)) { try { db.CreateCheckConstraint(tblName, colName, checkConstraintName, checkExpressions); } catch (Exception ex) { // Don't abort on such a error Log.ErrorFormat("unable to create CHECK constraint for ValueType Property '{0}' in '{1}': {2}", colName, tblName, ex.Message); } } else Log.ErrorFormat("unable to create CHECK constraint for ValueType Property '{0}' in '{1}': column contains invalid NULLs or superfluous values", colName, tblName); }
public void DoChangeValueTypeProperty_To_NotNullable(ObjectClass objClass, ValueTypeProperty prop, string prefix) { var savedProp = savedSchema.FindPersistenceObject<ValueTypeProperty>(prop.ExportGuid); if (!PreMigration(PropertyMigrationEventType.ChangeToNotNullable, savedProp, prop)) return; var tblName = objClass.GetTableRef(db); var colName = Construct.ColumnName(prop, prefix); var def = SchemaManager.GetDefaultConstraint(prop); if (def == null && db.CheckColumnContainsNulls(tblName, colName)) { Log.ErrorFormat("column '{0}.{1}' contains NULL values and has no default contraint, cannot set NOT NULLABLE", tblName, colName); } else { if (def != null) { var isSimplyCheckable = objClass.GetTableMapping() == TableMapping.TPT || objClass.BaseObjectClass == null; var classes = objClass.AndChildren(c => c.SubClasses).Select(cls => Construct.DiscriminatorValue(cls)).ToList(); WriteDefaultValue(tblName, colName, def, isSimplyCheckable ? null : classes); } db.AlterColumn(tblName, colName, prop.GetDbType(), prop.GetSize(), prop.GetScale(), prop.IsNullable(), null /* don't change contraints */); } PostMigration(PropertyMigrationEventType.ChangeToNotNullable, savedProp, prop); }