特定のプロパティにデフォルト値を与える「エレガントな」方法はありますか?
多分DataAnnotationsによるもので、次のようなものです:
[DefaultValue("true")]
public bool Active { get; set; }
ありがとうございました。
特定のプロパティにデフォルト値を与える「エレガントな」方法はありますか?
多分DataAnnotationsによるもので、次のようなものです:
[DefaultValue("true")]
public bool Active { get; set; }
ありがとうございました。
コードの最初の移行を手動で編集することで実行できます。
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
長くなりましたが、他の方のためにメモを残します。属性で必要なことを達成し、モデル クラス フィールドをその属性で必要に応じて装飾しました。
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
これらの2つの記事の助けを得ました:
私がしたこと:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
public string DefaultValue { get; set; }
}
modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
private void SetAnnotatedColumn(ColumnModel col)
{
AnnotationValues values;
if (col.Annotations.TryGetValue("SqlDefaultValue", out values))
{
col.DefaultValueSql = (string)values.NewValue;
}
}
次に、Migration Configuration コンストラクターで、カスタム SQL ジェネレーターを登録します。
SetSqlGenerator("System.Data.SqlClient", new CustomMigrationSqlGenerator());
上記の回答は本当に役に立ちましたが、ソリューションの一部しか提供しませんでした。主な問題は、デフォルト値属性を削除するとすぐに、データベースの列に対する制約が削除されないことです。したがって、以前のデフォルト値は引き続きデータベースに残ります。
これは、属性の削除に関する SQL 制約の削除を含む、問題に対する完全な解決策です。DefaultValue
.NET Framework のネイティブ属性も再利用しています。
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }
これを機能させるには、 IdentityModels.csおよびConfiguration.csファイルを更新する必要があります。
ApplicationDbContext
クラスでこのメソッドを追加/更新します
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var convention = new AttributeToColumnAnnotationConvention<DefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.SingleOrDefault().Value.ToString());
modelBuilder.Conventions.Add(convention);
}
Configuration
次のように、カスタム Sql ジェネレーターを登録して、クラス コンストラクターを更新します。
internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
// DefaultValue Sql Generator
SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator());
}
}
次に、カスタム Sql ジェネレーター クラスを追加します ( Configuration.csファイルまたは別のファイルに追加できます)。
internal class DefaultValueSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
private int dropConstraintCount;
protected override void Generate(AddColumnOperation addColumnOperation)
{
SetAnnotatedColumn(addColumnOperation.Column, addColumnOperation.Table);
base.Generate(addColumnOperation);
}
protected override void Generate(AlterColumnOperation alterColumnOperation)
{
SetAnnotatedColumn(alterColumnOperation.Column, alterColumnOperation.Table);
base.Generate(alterColumnOperation);
}
protected override void Generate(CreateTableOperation createTableOperation)
{
SetAnnotatedColumns(createTableOperation.Columns, createTableOperation.Name);
base.Generate(createTableOperation);
}
protected override void Generate(AlterTableOperation alterTableOperation)
{
SetAnnotatedColumns(alterTableOperation.Columns, alterTableOperation.Name);
base.Generate(alterTableOperation);
}
private void SetAnnotatedColumn(ColumnModel column, string tableName)
{
if (column.Annotations.TryGetValue("SqlDefaultValue", out var values))
{
if (values.NewValue == null)
{
column.DefaultValueSql = null;
using var writer = Writer();
// Drop Constraint
writer.WriteLine(GetSqlDropConstraintQuery(tableName, column.Name));
Statement(writer);
}
else
{
column.DefaultValueSql = (string)values.NewValue;
}
}
}
private void SetAnnotatedColumns(IEnumerable<ColumnModel> columns, string tableName)
{
foreach (var column in columns)
{
SetAnnotatedColumn(column, tableName);
}
}
private string GetSqlDropConstraintQuery(string tableName, string columnName)
{
var tableNameSplitByDot = tableName.Split('.');
var tableSchema = tableNameSplitByDot[0];
var tablePureName = tableNameSplitByDot[1];
var str = $@"DECLARE @var{dropConstraintCount} nvarchar(128)
SELECT @var{dropConstraintCount} = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'{tableSchema}.[{tablePureName}]')
AND col_name(parent_object_id, parent_column_id) = '{columnName}';
IF @var{dropConstraintCount} IS NOT NULL
EXECUTE('ALTER TABLE {tableSchema}.[{tablePureName}] DROP CONSTRAINT [' + @var{dropConstraintCount} + ']')";
dropConstraintCount++;
return str;
}
}
モデル プロパティは「自動プロパティ」である必要はありませんが、そのほうが簡単です。そして、DefaultValue 属性は、実際には有益なメタデータにすぎません。ここで受け入れられた答えは、コンストラクター アプローチの 1 つの代替手段です。
public class Track
{
private const int DEFAULT_LENGTH = 400;
private int _length = DEFAULT_LENGTH;
[DefaultValue(DEFAULT_LENGTH)]
public int LengthInMeters {
get { return _length; }
set { _length = value; }
}
}
対。
public class Track
{
public Track()
{
LengthInMeters = 400;
}
public int LengthInMeters { get; set; }
}
これは、この特定のクラスを使用してデータを作成および消費するアプリケーションに対してのみ機能します。通常、データ アクセス コードが集中化されている場合、これは問題になりません。すべてのアプリケーションで値を更新するには、データソースを構成してデフォルト値を設定する必要があります。Devi's answerは、移行、SQL、またはデータ ソースが話す言語を使用してそれを行う方法を示しています。
私がしたことは、エンティティのコンストラクターで値を初期化したことです
注: DefaultValue 属性は、プロパティの値を自動的に設定しません。自分で設定する必要があります。
@SedatKapanoglu のコメントの後、機能するすべてのアプローチを追加します。彼が正しかったため、流暢な API を使用するだけでは機能しません。
1- カスタム コード ジェネレーターを作成し、ColumnModel の Generate をオーバーライドします。
public class ExtendedMigrationCodeGenerator : CSharpMigrationCodeGenerator
{
protected override void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false)
{
if (column.Annotations.Keys.Contains("Default"))
{
var value = Convert.ChangeType(column.Annotations["Default"].NewValue, column.ClrDefaultValue.GetType());
column.DefaultValue = value;
}
base.Generate(column, writer, emitName);
}
}
2- 新しいコード ジェネレーターを割り当てます。
public sealed class Configuration : DbMigrationsConfiguration<Data.Context.EfSqlDbContext>
{
public Configuration()
{
CodeGenerator = new ExtendedMigrationCodeGenerator();
AutomaticMigrationsEnabled = false;
}
}
3- 流暢な API を使用して注釈を作成します。
public static void Configure(DbModelBuilder builder){
builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0);
}
それは簡単です!必要な注釈を付けるだけです。
[Required]
public bool MyField { get; set; }
結果の移行は次のようになります。
migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);
true が必要な場合は、データベースを更新する前に移行で defaultValue を true に変更します。
.NET Core 3.1 では、モデル クラスで次のことができます。
public bool? Active { get; set; }
DbContext OnModelCreating で、デフォルト値を追加します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foundation>()
.Property(b => b.Active)
.HasDefaultValueSql("1");
base.OnModelCreating(modelBuilder);
}
データベースで次のようになります
注:プロパティにnull許容(bool?)がない場合、次の警告が表示されます
The 'bool' property 'Active' on entity type 'Foundation' is configured with a database-generated default. This default will always be used for inserts when the property has the value 'false', since this is the CLR default for the 'bool' type. Consider using the nullable 'bool?' type instead so that the default will only be used for inserts when the property value is 'null'.
うーん...私は最初にDBを行います。その場合、これは実際にははるかに簡単です。EF6でしょ?モデルを開き、デフォルトを設定する列を右クリックしてプロパティを選択すると、「DefaultValue」フィールドが表示されます。それを入力して保存するだけです。それはあなたのためにコードを設定します。
あなたの走行距離は最初にコードによって異なる場合がありますが、私はそれを扱っていません。
他の多くのソリューションの問題点は、最初は機能するかもしれませんが、モデルを再構築するとすぐに、マシン生成ファイルに挿入したカスタム コードが破棄されることです。
この方法は、edmx ファイルに追加のプロパティを追加することで機能します。
<EntityType Name="Thingy">
<Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />
そして、必要なコードをコンストラクターに追加することによって:
public Thingy()
{
this.Iteration = 1;