Definir valores explícitos para as propriedades geradasSetting Explicit Values for Generated Properties

Uma propriedade gerada é uma propriedade cujo valor é gerado (o EF ou o banco de dados) quando a entidade é adicionada e/ou atualizada.A generated property is a property whose value is generated (either by EF or the database) when the entity is added and/or updated. Consulte propriedades gerado para obter mais informações.See Generated Properties for more information.

Pode haver situações em que você deseja definir um valor explícito para uma propriedade gerada, em vez de ter gerado.There may be situations where you want to set an explicit value for a generated property, rather than having one generated.

Dica

Você pode exibir este artigo exemplo no GitHub.You can view this article's sample on GitHub.

O modeloThe model

O modelo usado neste artigo contém uma única Employee entidade.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; }
}

Salvar um valor explícito durante adicionarSaving an explicit value during add

O Employee.EmploymentStarted está configurado para ter valores gerados pelo banco de dados para novas entidades (usando um valor padrão).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())");

O código a seguir insere dois funcionários no banco de dados.The following code inserts two employees into the database.

  • Para a primeira, nenhum valor é atribuído a Employee.EmploymentStarted propriedade, portanto, ele permanece definido como o valor padrão CLR DateTime.For the first, no value is assigned to Employee.EmploymentStarted property, so it remains set to the CLR default value for DateTime.
  • Para o segundo, configuramos um valor explícito de 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);
    }
}

Saída mostra que o banco de dados gerou um valor para o primeiro funcionário e nosso valor explícito foi usado para a segunda.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

Valores explícitos em colunas de identidade do SQL ServerExplicit values into SQL Server IDENTITY columns

Por convenção o Employee.EmployeeId propriedade é um repositório gerado IDENTITY coluna.By convention the Employee.EmployeeId property is a store generated IDENTITY column.

Na maioria das situações, a abordagem mostrada acima funcionará para propriedades de chave.For most situations, the approach shown above will work for key properties. No entanto, para inserir valores explícitos em um SQL Server IDENTITY coluna, é necessário habilitar manualmente IDENTITY_INSERT antes de chamar SaveChanges().However, to insert explicit values into a SQL Server IDENTITY column, you need to manually enable IDENTITY_INSERT before calling SaveChanges().

Observação

Temos um solicitação de recurso em nossa lista de pendências para fazer isso automaticamente dentro do provedor 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);
    }
}

Saída mostra que as ids fornecidas foram salvos no banco de dados.Output shows that the supplied ids were saved to the database.

100: John Doe
101: Jane Doe

Definir um valor explícito durante a atualizaçãoSetting an explicit value during update

O Employee.LastPayRaise está configurado para ter valores gerados pelo banco de dados durante as atualizações.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;

Observação

Por padrão, o núcleo de EF lançará uma exceção se você tentar salvar um valor explícito para uma propriedade que está configurado para ser gerado durante a atualização.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. Para evitar isso, você precisa passar para os metadados de nível inferior API e definir o AfterSaveBehavior (conforme mostrado acima).To avoid this, you need to drop down to the lower level metadata API and set the AfterSaveBehavior (as shown above).

Observação

Alterações no EF Core 2.0: nas versões anteriores, o comportamento de salvar After foi controlado por meio de IsReadOnlyAfterSave sinalizador.Changes in EF Core 2.0: In previous releases the after-save behavior was controlled through the IsReadOnlyAfterSave flag. Esse sinalizador foi obsoleto e substituído por AfterSaveBehavior.This flag has been obsoleted and replaced by AfterSaveBehavior.

Também há um gatilho no banco de dados para gerar valores para o LastPayRaise coluna durante UPDATE operações.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

O código a seguir aumenta o salário de dois funcionários no banco de dados.The following code increases the salary of two employees in the database.

  • Para o primeiro, nenhum valor é atribuído à Employee.LastPayRaise propriedade, portanto, ele permanece definido como null.For the first, no value is assigned to Employee.LastPayRaise property, so it remains set to null.
  • Para o segundo, configuramos um valor explícito de uma semana atrás (elevar back desde o pagamento).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);
    }
}

Saída mostra que o banco de dados gerou um valor para o primeiro funcionário e nosso valor explícito foi usado para a segunda.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