Skip to content

Commit

Permalink
Some corrections and additions to value generation (#4172)
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Jan 5, 2023
1 parent 1a32092 commit fbb3851
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
16 changes: 7 additions & 9 deletions entity-framework/core/modeling/generated-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,13 @@ Similarly, a property can be configured to have its value generated on add or up

***

> [!WARNING]
> Unlike with default values or computed columns, we are not specifying *how* the values are to be generated; that depends on the database provider being used. Database providers may automatically set up value generation for some property types, but others may require you to manually set up how the value is generated.
>
> For example, on SQL Server, when a GUID property is configured as value generated on add, the provider automatically performs value generation client-side, using an algorithm to generate optimal sequential GUID values. However, specifying <xref:Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder.ValueGeneratedOnAdd%2A> on a DateTime property will have no effect ([see the section below for DateTime value generation](#datetime-value-generation)).
>
> Similarly, byte[] properties that are configured as generated on add or update and marked as concurrency tokens are set up with the rowversion data type, so that values are automatically generated in the database. However, specifying <xref:Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder.ValueGeneratedOnAdd%2A> has no effect.
>
> [!NOTE]
> Depending on the database provider being used, values may be generated client side by EF or in the database. If the value is generated by the database, then EF may assign a temporary value when you add the entity to the context; this temporary value will then be replaced by the database generated value during `SaveChanges()`. For more information, [see the docs on temporary values](xref:core/change-tracking/explicit-tracking#temporary-values).
Unlike with default values or computed columns, we are not specifying *how* the values are to be generated; that depends on the database provider being used. Database providers may automatically set up value generation for some property types, but others may require you to manually set up how the value is generated.

For example, on SQL Server, when a GUID property is configured as a primary key, the provider automatically performs value generation client-side, using an algorithm to generate optimal sequential GUID values. However, specifying <xref:Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder.ValueGeneratedOnAdd%2A> on a DateTime property will have no effect ([see the section below for DateTime value generation](#datetime-value-generation)).

Similarly, byte[] properties that are configured as generated on add or update and marked as concurrency tokens are set up with the rowversion data type, so that values are automatically generated in the database. However, specifying <xref:Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder.ValueGeneratedOnAdd%2A> has no effect.

Consult your provider's documentation for the specific value generation techniques it supports. The SQL Server value generation documentation can be found [here](xref:core/providers/sql-server/value-generation).

## Date/time value generation

Expand Down
46 changes: 46 additions & 0 deletions entity-framework/core/providers/sql-server/value-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,49 @@ By default, SQL Server doesn't allow inserting explicit values into IDENTITY col
As an alternative to IDENTITY columns, you can use standard sequences. This can be useful in various scenarios; for example, you may want to have multiple columns drawing their default values from a single sequence.

SQL Server allows you to create sequences and use them as detailed in [the general page on sequences](xref:core/modeling/sequences). It's up to you to configure your properties to use sequences via `HasDefaultValueSql()`.

## GUIDs

For GUID primary keys, the provider automatically generates optimal sequential values, similar to SQL Server's [NEWSEQUENTIALID](/sql/t-sql/functions/newsequentialid-transact-sql) function. Generating the value on the client is more efficient in some scenarios, i.e. an extra database round trip isn't needed to get the database-generated value, when a dependent is also being inserted that references that key.

To have EF generate the same sequential GUID values for non-key properties, configure them as follows:

```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().Property(b => b.Guid).HasValueGenerator(typeof(SequentialGuidValueGenerator));
}
```

## Rowversions

SQL Server has the [`rowversion`](/t-sql/data-types/rowversion-transact-sql) data type, which automatically changes whenever the row is updated. This makes it very useful as a concurrency token, for managing cases where the same row is simultaneously updated by multiple transactions.

To fully understand concurrency tokens and how to use them, read the dedicated page on [concurrency conflicts](xref:core/saving/concurrency). To map a `byte[]` property to a `rowversion` column, configure it as follows:

### [Data Annotations](#tab/data-annotations)

```c#
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }

[Timestamp]
public byte[] Version { get; set; }
}
```

### [Fluent API](#tab/fluent-api)

```c#
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.Property(p => p.Version)
.IsRowVersion();
}
```

***

0 comments on commit fbb3851

Please sign in to comment.