エンティティ・フレームワークは、問合せへの挿入にデフォルト値を持つ列を含まない

c# entity-framework entity-framework-core

質問

私はいくつかの列がデフォルト値で定義されているモデルを持っています

table.Column<bool>(nullable: false, defaultValueSql: "1")

context.SaveChanges()を使用してデータベースに新しいエンティティを保存すると、Entity Frameworkが生成するクエリへの挿入にデフォルト値の列が含まれないことに気付きました。そのため、データベースで生成される値は、私がモデルに渡しているもの。

これらのプロパティをコードで設定できるように、コンテキスト内にいくつかのプロパティを設定する必要がありますか?私はEF Coreを使用していますが、これがすべてのEFバージョンの一般的な動作であるかどうかはわかりません。

更新:コードはかなりシンプルです。これは私が持っているものの擬似コードです。 Modelには、上記のtable.Column<bool>(nullable: false, defaultValueSql: "1")ような制約で定義されたいくつかのプロパティがあります。

MyBooleanProperty列を例として使用します。私は奉仕している:

var newModel = new GEAddress();
newModel = someEntity.MyBooleanProperty; //it is false,but ends up as 1 in the database

私はUnit Of WorkとRepositoriesを使用しているので

_unitOfWork.MyModelRepository.Add(newModel);
_unitOfWork.SaveChanges();

VSの出力ウィンドウで、 INSERT INTOクエリのすべてのプロパティをどのように送信するのかを確認し、デフォルト値のプロパティに対してSELECTします。結果は、デフォルト値の列を除いて、送信したすべての値を持つデータベースのnewModelです。これらのテーブルを必要とする別のシステムで使用されているため、これらのテーブルの構成を変更することはできません。

私はこれが解決策以上に起こっている理由について説明したいと思います。私はこれを回避することができますが、なぜこの現象が起こっているのか知りたいのですが

受け入れられた回答

私はこれをバグと呼ぶだろう。

私は一緒に簡単なテスト、いくつかのデフォルトを持つクラスをスナップ:

public class Test
{
    public int ID { get; set; }
    public int IntDef { get; set; }
    public bool BoolDef { get; set; }
    public DateTime? DateDef { get; set; }
}

(DateTimeはNULLに設定可能であることに注意してください)

マッピング:

modelBuilder.Entity<Test>().HasKey(a => a.ID);
modelBuilder.Entity<Test>().Property(s => s.DateDef).HasDefaultValueSql("GETDATE()");
modelBuilder.Entity<Test>().Property(s => s.IntDef).HasDefaultValueSql("1");
modelBuilder.Entity<Test>().Property(s => s.BoolDef).HasDefaultValue(true);
// Equivalent:
// modelBuilder.Entity<Test>().Property(s => s.BoolDef).HasDefaultValueSql("1");

テーブルを作成するSQL文:

CREATE TABLE [Tests] (
    [ID] int NOT NULL IDENTITY,
    [BoolDef] bit NOT NULL DEFAULT 1,
    [DateDef] datetime2 DEFAULT (GETDATE()),
    [IntDef] int NOT NULL DEFAULT (1),
    CONSTRAINT [PK_Tests] PRIMARY KEY ([ID])
);

値を設定せずに新しいTestを挿入すると、insert文は次のようになります。

INSERT INTO [Tests]
DEFAULT VALUES;
SELECT [ID], [BoolDef], [DateDef], [IntDef]
FROM [Tests]
WHERE @@ROWCOUNT = 1 AND [ID] = scope_identity();

3つのデフォルト値(および生成されたID値)が挿入後にデータベースから読み取られることがわかります。 [ところで、これはEF-Coreの新機能です。 EF6では、 DatabaseGeneratedOption.ComputedとしてマークされたID値および列値のみが、挿入(および更新)後にデータベースから読み取られました。

これは作成されたTestオブジェクトです:

ID IntDef BoolDef DateDef
1  1      True    21-11-16 19:52:56 

今度は新しいTestを挿入してすべての値を代入しますが、楽しみのためにnull以外の型のデフォルト値を使用します。

var item = new Test
{ 
    IntDef = default(int), // 0 
    BoolDef = default(bool), // false
    DateDef = default(DateTime), // 01-01-01 0:00:00
};

ここにSQL文があります:

exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Tests] ([DateDef])
VALUES (@p0);
SELECT [ID], [BoolDef], [IntDef]
FROM [Tests]
WHERE @@ROWCOUNT = 1 AND [ID] = scope_identity();
',N'@p0 datetime2(7)',@p0='0001-01-01 00:00:00'

もちろん、EFにはデフォルト値が意図的に割り当てられていると推測する方法はありません。したがって、表示されるように、null可能なDateTime列の場合にのみ、割り当てられた値が挿入されます。null不可能な列には挿入されません。 DateDefの値は、挿入後にデータベースから読み取られません。

エンティティの値は次のとおりです。

ID IntDef BoolDef DateDef
1  1      True    01-01-01 0:00:00 

エンティティを保存した後に期待するものではありません。

つまり、

EF-Coreでデフォルト値を持つプロパティーを構成し、このデフォルト値が.Netのデフォルト値と異なる場合、.Netタイプのデフォルト値を持つエンティティー (ブール値の場合はfalseなど)を挿入することはできません

私はこれが深刻なバグだと思うかもしれません。おそらくデフォルトに関する新しいEF-Coreの動作を不適格にするかもしれません。

添加
Ivanのコメントで述べたように、 ValueGeneratedNever()追加することで、EFがデフォルト値を設定するのを止めることができます。

modelBuilder.Entity<Test>().Property(s => s.IntDef)
            .HasDefaultValueSql("1").ValueGeneratedNever();

これで値はそのまま保存され、EFは挿入と更新後に値を読み取らなくなります。私は、null不可能なプロパティのデフォルトを定義することは有用ではないと思います。


EF Core 1.1.0プレビューでテスト済み。


人気のある回答

適切な属性で計算されたプロパティをマークしないと

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]  

efは、プロパティ値を持つinsert文を生成します。
更新中、EFは、変更された値のみを挿入するUPDATE文SET句を生成します。

上記の属性を使用することができるDBMSによってのみプロパティが生成された場合は、エンティティをラップするクラスのコンストラクタにデフォルト値を挿入する必要があります。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ