생성된 속성에 대한 명시적 값 설정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

이 문서에 사용된 모델에는 단일 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())");

다음 코드에서는 데이터베이스에 두 명의 직원을 삽입합니다.The following code inserts two employees into the database.

  • 첫 번째의 경우 Employee.EmploymentStarted 속성에 값이 할당되지 않으므로 DateTime에 대한 CLR 기본값으로 설정됩니다.For the first, no value is assigned to Employee.EmploymentStarted property, so it remains set to the CLR default value for DateTime.
  • 두 번째의 경우 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);
    }
}

출력에서는 데이터베이스가 첫 번째 직원에 대해서는 값을 생성하고 두 번째에는 명시적 값을 사용했음을 보여줍니다.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 IDENTITY 열의 명시적 값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 열에 명시적 값을 삽입하려면 SaveChanges()를 호출하기 전에 IDENTITY_INSERT를 수동으로 사용해야 합니다.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.ExecuteSqlRaw("SET IDENTITY_INSERT dbo.Employees ON");
        context.SaveChanges();
        context.Database.ExecuteSqlRaw("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.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);

참고

기본적으로 업데이트 중에 생성되도록 구성된 속성에 대한 명시적 값을 저장하려고 하면 EF Core에서 예외를 throw합니다.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 Core 2.0의 변경 내용: 이전 릴리스에서는 after-save 동작이 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.

데이터베이스에는 UPDATE 작업 중에 LastPayRaise 열에 대한 값을 생성하는 트리거도 있습니다.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

다음 코드에서는 데이터베이스에서 두 직원의 급여를 올립니다.The following code increases the salary of two employees in the database.

  • 첫 번째의 경우 Employee.LastPayRaise 속성에 값이 할당되지 않으므로 null로 설정됩니다.For the first, no value is assigned to Employee.LastPayRaise property, so it remains set to null.
  • 두 번째의 경우 1주일 전(급여 인상 날짜 소급)이라는 명시적 값을 설정했습니다.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);
    }
}

출력에서는 데이터베이스가 첫 번째 직원에 대해서는 값을 생성하고 두 번째에는 명시적 값을 사용했음을 보여줍니다.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