生成的值Generated Values

值生成模式Value Generation Patterns

有三种可用于属性的值生成模式:There are three value generation patterns that can be used for properties:

  • 无值生成No value generation
  • 在添加时生成值Value generated on add
  • 在添加或更新时生成值Value generated on add or update

无值生成No value generation

没有值生成意味着,需始终提供要保存到数据库的有效值。No value generation means that you will always supply a valid value to be saved to the database. 必须先将有效的值赋予新的实体,再将这些新的实体添加到上下文中。This valid value must be assigned to new entities before they are added to the context.

在添加时生成值Value generated on add

在添加时生成值,意思是为新实体生成值。Value generated on add means that a value is generated for new entities.

根据所用数据库提供程序的不同,值可能会通过 EF 在客户端生成或者由数据库生成。Depending on the database provider being used, values may be generated client side by EF or in the database. 如果由数据库生成值,则当你将实体添加到上下文时,EF 可能会赋予一个临时值。If the value is generated by the database, then EF may assign a temporary value when you add the entity to the context. 而后,由数据库生成的值会在 SaveChanges() 过程中替换这个临时值。This temporary value will then be replaced by the database generated value during SaveChanges().

如果将一个实体添加到已经为属性赋予值的上下文,则 EF 会尝试插入该值而不是生成新值。If you add an entity to the context that has a value assigned to the property, then EF will attempt to insert that value rather than generating a new one. 属性被认为已赋值的前提是该属性未被赋予 CLR 默认值(string 的默认值为 nullint 的默认值为 0Guid.Empty 的默认值为 Guid,等等)。A property is considered to have a value assigned if it is not assigned the CLR default value (null for string, 0 for int, Guid.Empty for Guid, etc.). 有关详细信息,请参阅已生成属性的显式值For more information, see Explicit values for generated properties.

警告

如何为添加的实体生成值取决于所用数据库提供程序。How the value is generated for added entities will depend on the database provider being used. 数据库提供程序可能会为某些属性类型自动设置值的生成,但其他的属性类型可能要求你手动设置值的生成方式。Database providers may automatically setup value generation for some property types, but others may require you to manually setup how the value is generated.

例如,使用 SQL Server 时,会自动生成 GUID 属性的值(使用 SQL Server 的顺序 GUID 算法)。For example, when using SQL Server, values will be automatically generated for GUID properties (using the SQL Server sequential GUID algorithm). 但是,如果指定在添加时生成 DateTime 属性,则必须设置生成值的方法。However, if you specify that a DateTime property is generated on add, then you must setup a way for the values to be generated. 若要执行此操作,一种方法是配置 GETDATE() 的默认值,请参阅默认值One way to do this, is to configure a default value of GETDATE(), see Default Values.

在添加或更新时生成值Value generated on add or update

在添加或更新时生成值,意味着在每次保存该记录(插入或更新)时生成新值。Value generated on add or update means that a new value is generated every time the record is saved (insert or update).

就像value generated on add一样,如果为一个实体的新增实例上的属性指定了一个值,则 EF 会尝试插入该值而不是生成新值。Like value generated on add, if you specify a value for the property on a newly added instance of an entity, that value will be inserted rather than a value being generated. 还可以在更新时设置显式值。It is also possible to set an explicit value when updating. 有关详细信息,请参阅已生成属性的显式值For more information, see Explicit values for generated properties.

警告

如何在添加和更新实体时生成值取决于所用数据库提供程序。How the value is generated for added and updated entities will depend on the database provider being used. 数据库提供程序可能会为某些属性类型自动设置值的生成,但其他的属性类型会要求你手动设置值的生成方式。Database providers may automatically setup value generation for some property types, while others will require you to manually setup how the value is generated.

例如,在使用 SQL Server 时,设置为在添加和更新时生成值并标注为并发标记的 byte[] 属性会被设置为 rowversion 数据类型,以便在数据库中生成值。For example, when using SQL Server, byte[] properties that are set as generated on add or update and marked as concurrency tokens, will be setup with the rowversion data type - so that values will be generated in the database. 但是,如果指定在添加或更新时生成 DateTime 属性,则必须设置生成值的方法。However, if you specify that a DateTime property is generated on add or update, then you must setup a way for the values to be generated. 若要执行此操作,一种方法是配置 GETDATE() 的默认值(请参阅默认值)以生成新行的值。One way to do this, is to configure a default value of GETDATE() (see Default Values) to generate values for new rows. 然后即可使用数据库触发器在更新过程中生成值(如下面的示例触发器所示)。You could then use a database trigger to generate values during updates (such as the following example trigger).

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

约定Conventions

按照约定,类型为 short、int、long、或 Guid 的非复合主键会被设置在添加时生成值。By convention, non-composite primary keys of type short, int, long, or Guid will be setup to have values generated on add. 所有其他属性会被设置为不生成值。All other properties will be setup with no value generation.

数据注释Data Annotations

没有值生成 (数据批注)No value generation (Data Annotations)

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

在添加时生成值(数据注释)Value generated on add (Data Annotations)

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime Inserted { get; set; }
}

警告

这只是让 EF 知道为已添加的实体生成值,并不保证 EF 会设置实际机制来生成值。This just lets EF know that values are generated for added entities, it does not guarantee that EF will setup the actual mechanism to generate values. 请参阅在添加时生成值部分,了解更多详细信息。See Value generated on add section for more details.

在添加或更新时生成值(数据注释)Value generated on add or update (Data Annotations)

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastUpdated { get; set; }
}

警告

这只是让 EF 知道为添加或更新的实体生成值,并不保证 EF 会设置实际机制来生成值。This just lets EF know that values are generated for added or updated entities, it does not guarantee that EF will setup the actual mechanism to generate values. 请参阅在添加或更新时生成值部分,了解更多详细信息。See Value generated on add or update section for more details.

Fluent APIFluent API

Fluent API 可用于更改某一给定属性的值生成模式。You can use the Fluent API to change the value generation pattern for a given property.

没有值生成 (Fluent API)No value generation (Fluent API)

modelBuilder.Entity<Blog>()
    .Property(b => b.BlogId)
    .ValueGeneratedNever();

在添加时生成值 (Fluent API)Value generated on add (Fluent API)

modelBuilder.Entity<Blog>()
    .Property(b => b.Inserted)
    .ValueGeneratedOnAdd();

警告

ValueGeneratedOnAdd() 只是让 EF 知道为添加的实体生成值,并不保证 EF 会设置实际机制来生成值。ValueGeneratedOnAdd() just lets EF know that values are generated for added entities, it does not guarantee that EF will setup the actual mechanism to generate values. 请参阅在添加时生成值部分,了解更多详细信息。See Value generated on add section for more details.

在添加或更新时生成值 (Fluent API)Value generated on add or update (Fluent API)

modelBuilder.Entity<Blog>()
    .Property(b => b.LastUpdated)
    .ValueGeneratedOnAddOrUpdate();

警告

这只是让 EF 知道为添加或更新的实体生成值,并不保证 EF 会设置实际机制来生成值。This just lets EF know that values are generated for added or updated entities, it does not guarantee that EF will setup the actual mechanism to generate values. 请参阅在添加或更新时生成值部分,了解更多详细信息。See Value generated on add or update section for more details.