生成されたプロパティの明示的な値の設定Setting Explicit Values for Generated Properties

生成されたプロパティは、(または使用して、EF データベース) の値が生成されるプロパティ、エンティティを追加または更新するときにします。A generated property is a property whose value is generated (either by EF or the database) when the entity is added and/or updated. 参照してください生成プロパティ詳細についてはします。See Generated Properties for more information.

生成されたことのではなく、生成されるプロパティの明示的な値を設定する場合があります。There may be situations where you want to set an explicit value for a generated property, rather than having one generated.

ヒント

この記事を表示するサンプルGitHub でします。You can view this article's sample on GitHub.

モデルThe model

この記事で使用されるモデルには、1 つが含まれているEmployeeエンティティです。The model used in this article contains a single Employee entity.

public class Employee
{
    public int EmployeeId { get; set; }
    public string Name { get; set; }
    public DateTime EmploymentStarted { get; set; }
    public int Salary { get; set; }
    public DateTime? LastPayRaise { get; set; }
}

追加中に、明示的な値を保存します。Saving an explicit value during add

Employee.EmploymentStartedプロパティ (既定値を使用して) 新しいエンティティをデータベースによって生成された値を持つように構成します。The Employee.EmploymentStarted property is configured to have values generated by the database for new entities (using a default value).

modelBuilder.Entity<Employee>()
    .Property(b => b.EmploymentStarted)
    .HasDefaultValueSql("CONVERT(date, GETDATE())");

次のコードは、データベースに 2 人の従業員を挿入します。The following code inserts two employees into the database.

  • 1 つ目の値が割り当てられていないにEmployee.EmploymentStartedプロパティ、そのままとなりますので、CLR の既定値に設定DateTimeです。For the first, no value is assigned to Employee.EmploymentStarted property, so it remains set to the CLR default value for DateTime.
  • 明示的な値を設定して、2 番目の1-Jan-2000します。For the second, we have set an explicit value of 1-Jan-2000.
using (var context = new EmployeeContext())
{
    context.Employees.Add(new Employee { Name = "John Doe" });
    context.Employees.Add(new Employee { Name = "Jane Doe", EmploymentStarted = new DateTime(2000, 1, 1) });
    context.SaveChanges();

    foreach (var employee in context.Employees)
    {
        Console.WriteLine(employee.EmployeeId + ": " + employee.Name + ", " + employee.EmploymentStarted);
    }
}

出力は、データベースの最初の従業員の値を生成して、明示的な値は、2 番目に使用されたことを示しています。Output shows that the database generated a value for the first employee and our explicit value was used for the second.

1: John Doe, 1/26/2017 12:00:00 AM
2: Jane Doe, 1/1/2000 12:00:00 AM

SQL Server の ID 列に明示的な値Explicit values into SQL Server IDENTITY columns

慣例により、Employee.EmployeeIdプロパティは、ストアで生成されたIDENTITY列です。By convention the Employee.EmployeeId property is a store generated IDENTITY column.

ほとんどの場合、キー プロパティの前に示したアプローチは機能しません。For most situations, the approach shown above will work for key properties. ただし、SQL Server に明示的な値を挿入するIDENTITY列で、手動で有効にする必要がありますIDENTITY_INSERT呼び出す前にSaveChanges()です。However, to insert explicit values into a SQL Server IDENTITY column, you need to manually enable IDENTITY_INSERT before calling SaveChanges().

注意

お、機能要求自動的に行い、SQL Server プロバイダー内で、バックログにします。We have a feature request on our backlog to do this automatically within the SQL Server provider.

using (var context = new EmployeeContext())
{
    context.Employees.Add(new Employee { EmployeeId = 100, Name = "John Doe" });
    context.Employees.Add(new Employee { EmployeeId = 101, Name = "Jane Doe" });

    context.Database.OpenConnection();
    try
    {
        context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees ON");
        context.SaveChanges();
        context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees OFF");
    }
    finally
    {
        context.Database.CloseConnection();
    }


    foreach (var employee in context.Employees)
    {
        Console.WriteLine(employee.EmployeeId + ": " + employee.Name);
    }
}

出力は、指定された id がデータベースに保存されたことを示しています。Output shows that the supplied ids were saved to the database.

100: John Doe
101: Jane Doe

更新中に、明示的な値の設定Setting an explicit value during update

Employee.LastPayRaiseプロパティの更新中に、データベースによって生成された値を持つように構成します。The Employee.LastPayRaise property is configured to have values generated by the database during updates.

modelBuilder.Entity<Employee>()
    .Property(b => b.LastPayRaise)
    .ValueGeneratedOnAddOrUpdate();

modelBuilder.Entity<Employee>()
    .Property(b => b.LastPayRaise)
    .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;

注意

既定では、EF コアは更新中に生成される構成されているプロパティの明示的な値を保存しようとする場合に例外をスローします。By default, EF Core will throw an exception if you try to save an explicit value for a property that is configured to be generated during update. これを回避するのには、下位レベルのメタデータ API にドロップダウンを設定する必要があります、 AfterSaveBehavior (上記のように)。To avoid this, you need to drop down to the lower level metadata API and set the AfterSaveBehavior (as shown above).

注意

EF コア 2.0 での変更:後保存動作の制御を通じて以前のリリースで、IsReadOnlyAfterSaveフラグ。Changes in EF Core 2.0: In previous releases the after-save behavior was controlled through the IsReadOnlyAfterSave flag. このフラグを廃止され、置き換えAfterSaveBehaviorです。This flag has been obsoleted and replaced by AfterSaveBehavior.

値を生成するデータベースでトリガーされても、LastPayRaise中に列UPDATE操作します。There is also a trigger in the database to generate values for the LastPayRaise column during UPDATE operations.

CREATE TRIGGER [dbo].[Employees_UPDATE] ON [dbo].[Employees]
	AFTER UPDATE
AS
BEGIN
	SET NOCOUNT ON;
                  
	IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
                  
	IF UPDATE(Salary) AND NOT Update(LastPayRaise)
	BEGIN
		DECLARE @Id INT
		DECLARE @OldSalary INT
		DECLARE @NewSalary INT
          
		SELECT @Id = INSERTED.EmployeeId, @NewSalary = Salary        
		FROM INSERTED
          
		SELECT @OldSalary = Salary        
		FROM deleted
          
		IF @NewSalary > @OldSalary
		BEGIN
			UPDATE dbo.Employees
			SET LastPayRaise = CONVERT(date, GETDATE())
			WHERE EmployeeId = @Id
		END
	END
END

次のコードでは、データベース内の 2 つの従業員の給与が向上します。The following code increases the salary of two employees in the database.

  • 1 つ目の値が割り当てられていないにEmployee.LastPayRaiseプロパティの設定は、null にします。For the first, no value is assigned to Employee.LastPayRaise property, so it remains set to null.
  • 2 番目、1 週間前 (支払前までバック raise) の明示的な値が設定します。For the second, we have set an explicit value of one week ago (back dating the pay raise).
using (var context = new EmployeeContext())
{
    var john = context.Employees.Single(e => e.Name == "John Doe");
    john.Salary = 200;

    var jane = context.Employees.Single(e => e.Name == "Jane Doe");
    jane.Salary = 200;
    jane.LastPayRaise = DateTime.Today.AddDays(-7);

    context.SaveChanges();

    foreach (var employee in context.Employees)
    {
        Console.WriteLine(employee.EmployeeId + ": " + employee.Name + ", " + employee.LastPayRaise);
    }
}

出力は、データベースの最初の従業員の値を生成して、明示的な値は、2 番目に使用されたことを示しています。Output shows that the database generated a value for the first employee and our explicit value was used for the second.

1: John Doe, 1/26/2017 12:00:00 AM
2: Jane Doe, 1/19/2017 12:00:00 AM