Explizite Werte festlegen für die generierten EigenschaftenSetting Explicit Values for Generated Properties

Eine generierte Eigenschaft ist eine Eigenschaft, deren Wert generiert (entweder durch EF oder die Datenbank) Wenn die Entität hinzugefügt und/oder aktualisiert.A generated property is a property whose value is generated (either by EF or the database) when the entity is added and/or updated. Finden Sie unter Eigenschaften generiert für Weitere Informationen.See Generated Properties for more information.

Möglicherweise gibt es Situationen, in denen einen expliziten Wert für eine generierte Eigenschaft, anstatt ein generiertes festgelegt werden sollen.There may be situations where you want to set an explicit value for a generated property, rather than having one generated.

Tipp

Sie können anzeigen, dass dieser Artikel Beispiel auf GitHub.You can view this article's sample on GitHub.

Das ModellThe model

In diesem Artikel verwendete Modell enthält ein einziges Employee Entität.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; }
}

Speichern einen expliziten Wert während hinzufügenSaving an explicit value during add

Die Employee.EmploymentStarted Eigenschaft ist so konfiguriert, dass die Werte, die von der Datenbank für die neue Entitäten (mit einem Standardwert) generiert haben.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())");

Der folgende Code fügt zwei Mitarbeiter in der Datenbank.The following code inserts two employees into the database.

  • Für die erste Seite kein Wert zugewiesen wurde, um Employee.EmploymentStarted -Eigenschaft, sodass es weiterhin ist festgelegt auf den CLR-Standardwert für DateTime.For the first, no value is assigned to Employee.EmploymentStarted property, so it remains set to the CLR default value for DateTime.
  • Für die zweite haben wir einen expliziten Wert von setzen 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);
    }
}

Ausgabe zeigt, dass die Datenbank einen Wert für den ersten Mitarbeiter generiert und unsere explizite Wert für die zweite verwendet wurde.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

Explizite Werte in Identitätsspalten für SQL ServerExplicit values into SQL Server IDENTITY columns

Gemäß der Konvention die Employee.EmployeeId Eigenschaft ist ein speichergenerierte IDENTITY Spalte.By convention the Employee.EmployeeId property is a store generated IDENTITY column.

In den meisten Fällen funktioniert die oben gezeigte Ansatz für Schlüsseleigenschaften.For most situations, the approach shown above will work for key properties. Allerdings zum Einfügen von expliziter Werten in einer SQL Server IDENTITY Spalte müssen Sie manuell aktivieren IDENTITY_INSERT vor dem Aufruf SaveChanges().However, to insert explicit values into a SQL Server IDENTITY column, you need to manually enable IDENTITY_INSERT before calling SaveChanges().

Hinweis

Wir haben eine Funktionsanfrage auf unseren nachholbedarf automatisch in SQL Server-Anbieter dazu.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);
    }
}

Ausgabe zeigt an, dass die angegebenen Ids in der Datenbank gespeichert wurden.Output shows that the supplied ids were saved to the database.

100: John Doe
101: Jane Doe

Einen expliziten Wert festlegen, während der AktualisierungSetting an explicit value during update

Die Employee.LastPayRaise Eigenschaft ist so konfiguriert, dass die Werte, die von der Datenbank während eines Updates generiert haben.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;

Hinweis

Standardmäßig wird EF Core eine Ausnahme ausgelöst, wenn Sie versuchen, einen expliziten Wert für eine Eigenschaft zu speichern, die so konfiguriert ist, dass während des Updates generiert werden.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. Um dies zu vermeiden, müssen Sie Dropdown-Liste auf der unteren Ebene Metadaten-API und Festlegen der AfterSaveBehavior (siehe oben).To avoid this, you need to drop down to the lower level metadata API and set the AfterSaveBehavior (as shown above).

Hinweis

Änderungen in EF Core 2.0: In früheren Versionen wurde das Verhalten After speichern gesteuert, über die IsReadOnlyAfterSave Flag.Changes in EF Core 2.0: In previous releases the after-save behavior was controlled through the IsReadOnlyAfterSave flag. Dieses Flag veraltet und durch ersetzt wurde AfterSaveBehavior.This flag has been obsoleted and replaced by AfterSaveBehavior.

Es gibt auch ein Trigger in der Datenbank zum Generieren von Werten für die LastPayRaise Spalte während der UPDATE Vorgänge.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

Im folgende Code wird das Gehalt von zwei Mitarbeiter in der Datenbank erhöht.The following code increases the salary of two employees in the database.

  • Für die erste Seite kein Wert zugewiesen wurde, um Employee.LastPayRaise -Eigenschaft, sodass es weiterhin festgelegt ist auf Null.For the first, no value is assigned to Employee.LastPayRaise property, so it remains set to null.
  • Für die zweite haben wir einen expliziten Wert für eine Woche vor (zurück, bis des Lohns lösen) festgelegt.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);
    }
}

Ausgabe zeigt, dass die Datenbank einen Wert für den ersten Mitarbeiter generiert und unsere explizite Wert für die zweite verwendet wurde.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