生成された値

データベース列の値は、さまざまな方法で生成できます。主キー列は、自動インクリメントの整数、他の列には既定値または計算値などがあります。このページでは、EF Core で構成値を生成するためのさまざまなパターンについて詳しく説明します。

既定値

リレーショナルデータベースでは、既定値を使用して列を構成できます。その列の値を指定せずに行が挿入されると、既定値が使用されます。

プロパティの既定値を構成できます。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Rating)
        .HasDefaultValue(3);
}

既定値の計算に使用される SQL フラグメントを指定することもできます。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}

計算列

ほとんどのリレーショナルデータベースでは、データベース内の値を計算するように列を構成できます。通常は、他の列を参照する式を使用します。

modelBuilder.Entity<Person>()
    .Property(p => p.DisplayName)
    .HasComputedColumnSql("[LastName] + ', ' + [FirstName]");

上の例では、データベースからフェッチされるたびに値が計算される、 仮想 計算列が作成されます。 計算列を 格納 するように指定することもできます 。これ は、計算列が行のすべての更新で計算され、通常の列と共にディスクに格納されることを意味します。

modelBuilder.Entity<Person>()
    .Property(p => p.NameLength)
    .HasComputedColumnSql("LEN([LastName]) + LEN([FirstName])", stored: true);

注意

格納されている計算列の作成のサポートが EF Core 5.0 で追加されました。

主キー

慣例として、short、int、long、または Guid 型の非複合主キーは、アプリケーションによって値が提供されない場合に、挿入されたエンティティに対して値が生成されるように設定されます。 通常、データベースプロバイダーは必要な構成を行います。たとえば、SQL Server の数値主キーは、ID 列として自動的に設定されます。

詳細については、 キーに関するドキュメントを参照してください

値の生成を明示的に構成する

上で説明したように、主キーの値生成は自動的に設定されていますが、キー以外のプロパティに対しても同様の処理を行うことができ EF Core。 挿入されたエンティティに対して値が生成されるようにプロパティを構成するには、次のようにします。

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime Inserted { get; set; }
}

同様に、追加または更新時に値が生成されるようにプロパティを構成することもできます。

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastUpdated { get; set; }
}

警告

既定値または計算列とは異なり、ここでは値の生成 方法 を指定していません。これは、使用されているデータベースプロバイダーによって異なります。 データベースプロバイダーでは、一部のプロパティの型に対して自動的に値の生成が設定される場合がありますが、その他の場合は、値の生成方法を手動で設定する必要があります。

たとえば、SQL Server で、GUID プロパティが追加時に生成された値として構成されている場合、プロバイダーは、最適なシーケンシャル GUID 値を生成するアルゴリズムを使用して、値生成クライアント側を自動的に実行します。 ただし、DateTime プロパティにを指定しても ValueGeneratedOnAdd 効果はありません (datetime 値の生成については、以下のセクションを参照してください)。

同様に、add または update で生成されるように構成され、同時実行トークンとしてマークされている byte [] プロパティは、rowversion データ型を使用して設定されるので、データベースで値が自動的に生成されます。 ただし、を指定して ValueGeneratedOnAdd も効果はありません。

注意

使用するデータベースプロバイダーによっては、値が EF またはデータベースでクライアント側で生成される場合があります。 値がデータベースによって生成された場合、エンティティをコンテキストに追加するときに EF によって一時的な値が割り当てられることがあります。この一時値は、の間にデータベースによって生成された値に置き換えられ SaveChanges() ます。 詳細については、 一時値に関するドキュメントを参照してください

日付/時刻値の生成

一般的な要求では、列が最初に挿入された日時 (追加時に値が生成されたとき)、または最終更新日 (追加または更新時に生成された値) の日付/時刻を含むデータベース列が必要です。 これを行うにはさまざまな方法がありますが、EF Core プロバイダーは、通常、日付/時刻列に対して自動的に値の生成を設定しません。これを自分で構成する必要があります。

作成タイムスタンプ

通常、行の作成タイムスタンプを持つように日付/時刻列を構成する場合は、適切な SQL 関数を使用して既定値を構成することが重要です。 たとえば SQL Server では、次のものを使用できます。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}

必要に応じて、適切な関数を選択してください (例: GETDATE() vs. GETUTCDATE() )。

タイムスタンプの更新

格納されている計算列は最後に更新されたタイムスタンプを管理するための優れたソリューションであるように見えますが、データベースでは通常、計算列になどの関数を指定することはできません GETDATE() 。 別の方法として、データベーストリガーを設定して同じ効果を得ることもできます。

CREATE TRIGGER [dbo].[Blogs_UPDATE] ON [dbo].[Blogs]
    AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;

    DECLARE @Id INT

    SELECT @Id = INSERTED.BlogId
    FROM INSERTED

    UPDATE dbo.Blogs
    SET LastUpdated = GETDATE()
    WHERE BlogId = @Id
END

トリガーの作成の詳細については、 「移行における生の SQL の使用に関するドキュメント」を参照してください

オーバーライド (値の生成を)

プロパティは値の生成用に構成されていますが、多くの場合、その値を明示的に指定することもできます。 実際に動作するかどうかは、構成されている特定の値生成メカニズムによって異なります。列の既定値を使用するのではなく、明示的な値を指定することもできますが、計算列で同じことを行うことはできません。

明示的な値を使用して値の生成をオーバーライドするには、そのプロパティの型の CLR 既定値ではない任意の値 (for、for、for、など) にプロパティを設定するだけです null string 0 int Guid.Empty Guid

注意

既定では、明示的な値を SQL Server ID に挿入しようとすると失敗します。 回避策については、次のドキュメントを参照してください

追加または更新時に生成される値として構成されたプロパティの値を明示的に指定するには、次のようにプロパティを構成する必要もあります。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>().Property(b => b.LastUpdated)
        .ValueGeneratedOnAddOrUpdate()
        .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);
}

値の生成なし

前述のような特定のシナリオとは別に、プロパティには、通常、値の生成が構成されていません。つまり、データベースに保存される値を常に指定する必要があります。 この値は、コンテキストに追加する前に、新しいエンティティに割り当てる必要があります。

ただし、場合によっては、規約によって設定された値の生成を無効にすることが必要になる場合があります。 たとえば、int 型の主キーは、通常、追加時の値 (たとえば、SQL Server の id 列) として暗黙的に構成されます。 これは、次の方法で無効にできます。

public class Blog
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int BlogId { get; set; }

    public string Url { get; set; }
}