Skip to content

Commit

Permalink
Document [Precision] and [Unicode] attributes
Browse files Browse the repository at this point in the history
Closes dotnet#2977
Closes dotnet#3413
  • Loading branch information
roji committed Oct 12, 2021
1 parent 4ad5081 commit 690263b
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 89 deletions.
36 changes: 31 additions & 5 deletions entity-framework/core/modeling/entity-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Entity Properties - EF Core
description: How to configure and map entity properties using Entity Framework Core
author: roji
ms.date: 05/27/2020
ms.date: 10/12/2021
uid: core/modeling/entity-properties
---
# Entity Properties
Expand Down Expand Up @@ -80,9 +80,7 @@ In the following example, configuring a maximum length of 500 will cause a colum

### Precision and Scale

Starting with EFCore 5.0, you can use fluent API to configure the precision and scale. It tells the database provider how much storage is needed for a given column. It only applies to data types where the provider allows the precision and scale to vary - usually `decimal` and `DateTime`.

For `decimal` properties, precision defines the maximum number of digits needed to express any value the column will contain, and scale defines the maximum number of decimal places needed. For `DateTime` properties, precision defines the maximum number of digits needed to express fractions of seconds, and scale is not used.
Some relational data types support the precision and scale facets; these control what values can be stored, and how much storage is needed for the column. Which data types support precision and scale is database-dependent, but in most databases `decimal` and `DateTime` types do. For `decimal` properties, precision defines the maximum number of digits needed to express any value the column will contain, and scale defines the maximum number of decimal places needed. For `DateTime` properties, precision defines the maximum number of digits needed to express fractions of seconds, and scale is not used.

> [!NOTE]
> Entity Framework does not do any validation of precision or scale before passing data to the provider. It is up to the provider or data store to validate as appropriate. For example, when targeting SQL Server, a column of data type `datetime` does not allow the precision to be set, whereas a `datetime2` one can have precision between 0 and 7 inclusive.
Expand All @@ -91,17 +89,45 @@ In the following example, configuring the `Score` property to have precision 14

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

Precision and scale cannot currently be configured via data annotations.
> [!NOTE]
> The Data Annotation for configuring precision and scale was introduced in EF Core 6.0.
[!code-csharp[Main](../../../samples/core/Modeling/DataAnnotations/PrecisionAndScale.cs?name=PrecisionAndScale&highlight=4,6)]

> [!NOTE]
> Scale is never defined without first defining precision, so the Data Annotation for defining the scale is `[Precision(precision, scale)]`.
#### [Fluent API](#tab/fluent-api)

> [!NOTE]
> The Fluent API for configuring precision and scale was introduced in EF Core 5.0.
[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/PrecisionAndScale.cs?name=PrecisionAndScale&highlight=3-9)]

> [!NOTE]
> Scale is never defined without first defining precision, so the Fluent API for defining the scale is `HasPrecision(precision, scale)`.
***

### Unicode

In some relational databases, different types exist to represent Unicode and non-Unicode text data. For example, in SQL Server, `nvarchar(x)` is used to represent Unicode data in UTF-16, while `varchar(x)` is used to represent non-Unicode data (but see [these notes](xref:core/providers/sql-server/columns#unicode-and-utf-8) on SQL Server UTF-8 support). For databases which don't support this concept, configuring this has no effect.

Text properties are configured as Unicode by default. You can configure a column as non-Unicode as follows:

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

> [!NOTE]
> The Data Annotation for configuring Unicode was introduced in EF Core 6.0.
[!code-csharp[Main](../../../samples/core/Modeling/DataAnnotations/Unicode.cs?name=Unicode&highlight=6-7)]

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

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/Unicode.cs?name=Unicode&highlight=6-7)]

***

## Required and optional properties

A property is considered optional if it is valid for it to contain `null`. If `null` is not a valid value to be assigned to a property then it is considered to be a required property. When mapping to a relational database schema, required properties are created as non-nullable columns, and optional properties are created as nullable columns.
Expand Down
14 changes: 13 additions & 1 deletion entity-framework/core/providers/sql-server/columns.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@
title: Microsoft SQL Server Database Provider - Columns - EF Core
description: Column features specific to the Entity Framework Core SQL Server provider
author: roji
ms.date: 10/1/2021
ms.date: 10/12/2021
uid: core/providers/sql-server/columns
---
# Column features specific to the Entity Framework Core SQL Server provider

This page details column configuration options that are specific to the SQL Server provider.

## Unicode and UTF-8

SQL Server has two column types for storing textual data: [`nvarchar(x)`](/sql/t-sql/data-types/nchar-and-nvarchar-transact-sql) and [`varchar(x)`](/sql/t-sql/data-types/char-and-varchar-transact-sql); these have traditionally been used to hold Unicode data in the UTF-16 encoding and non-Unicode data, respectively. SQL Server 2019 [introduced](/sql/relational-databases/collations/collation-and-unicode-support#utf8) the ability to store UTF-8 Unicode data in `varchar(x)` columns.

Unfortunately, this does not currently work out-of-the-box with EF Core's SQL Server provider. To map a string property to a `varchar(x)` column, the Fluent or Data Annotation API is typically used to disable Unicode ([see these docs](xref:core/modeling/entity-properties#unicode)). While this causes the correct column type to be created, it also makes EF Core send database parameters in a way which is incompatible with UTF-8 data: `DbType.AnsiString` is used (signifying non-Unicode data), but `DbType.String` is needed to properly send Unicode data.

To summarize, follow the following step to store UTF-8 data in SQL Server:

* Configure the collation for the property with one of SQL Server's UTF-8 collations; these have a `UTF8` suffix ([see the docs on collation](xref:core/modeling/entity-properties##column-collations)).
* Configure the string property as Unicode (the default); this will cause EF Core to create an `nvarchar(x)` column.
* Edit the migrations and manually set the column type to `varchar(x)` intead.

## Sparse columns

> [!NOTE]
Expand Down
2 changes: 1 addition & 1 deletion entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md
Original file line number Diff line number Diff line change
Expand Up @@ -2476,7 +2476,7 @@ Starting with EF Core 6.0, a string property can now be mapped to a non-Unicode
public string Isbn { get; set; }
}
-->
[!code-csharp[BookEntityType](../../../../samples/core/Miscellaneous/NewInEFCore6/UnicodeAttributeSample.cs?name=BookEntityType)]
[!code-csharp[BookEntityType](../../../../samples/core/Modeling/DataAnnotations/Unicode.cs?name=Unicode&highlight=6-7)]

Since ISBNs cannot contain any non-unicode characters, the `Unicode` attribute will cause a non-Unicode string type to be used. In addition, `MaxLength` is used to limit the size of the database column. For example, when using SQL Server, this results in a database column of `varchar(22)`:

Expand Down
80 changes: 0 additions & 80 deletions samples/core/Miscellaneous/NewInEFCore6/UnicodeAttributeSample.cs

This file was deleted.

4 changes: 2 additions & 2 deletions samples/core/Modeling/DataAnnotations/DataAnnotations.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>EFModeling.DataAnnotations</RootNamespace>
<AssemblyName>EFModeling.DataAnnotations</AssemblyName>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0-rc.1.21452.10" />
</ItemGroup>

</Project>
21 changes: 21 additions & 0 deletions samples/core/Modeling/DataAnnotations/PrecisionAndScale.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using Microsoft.EntityFrameworkCore;

namespace EFModeling.DataAnnotations.PrecisionAndScale
{
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
}

#region PrecisionAndScale
public class Blog
{
public int BlogId { get; set; }
[Precision(14, 2)]
public decimal Score { get; set; }
[Precision(3)]
public DateTime LastUpdated { get; set; }
}
#endregion
}
22 changes: 22 additions & 0 deletions samples/core/Modeling/DataAnnotations/UnicodeAttributeSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;

namespace EFModeling.DataAnnotations.Unicode
{
internal class MyContext : DbContext
{
public DbSet<Book> Books { get; set; }
}

#region Unicode
public class Book
{
public int Id { get; set; }
public string Title { get; set; }

[Unicode(false)]
[MaxLength(22)]
public string Isbn { get; set; }
}
#endregion
}

0 comments on commit 690263b

Please sign in to comment.