Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document check constraints #3454

Merged
merged 1 commit into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions entity-framework/core/modeling/indexes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Indexes - EF Core
description: Configuring indexes in an Entity Framework Core model
author: roji
ms.date: 12/16/2019
ms.date: 10/1/2021
uid: core/modeling/indexes
---
# Indexes
Expand All @@ -13,14 +13,14 @@ You can specify an index over a column as follows:

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

[!code-csharp[Main](../../../samples/core/Modeling/DataAnnotations/Index.cs?name=Index&highlight=1)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/DataAnnotations/Index.cs?name=Index&highlight=1)]

> [!NOTE]
> Configuring indexes via Data Annotations has been introduced in EF Core 5.0.

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

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/Index.cs?name=Index&highlight=4)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/Index.cs?name=Index&highlight=4)]

***

Expand All @@ -35,11 +35,11 @@ An index can also span more than one column:

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

[!code-csharp[Main](../../../samples/core/Modeling/DataAnnotations/IndexComposite.cs?name=Composite&highlight=1)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/DataAnnotations/IndexComposite.cs?name=Composite&highlight=1)]

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

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/IndexComposite.cs?name=Composite&highlight=4)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/IndexComposite.cs?name=Composite&highlight=4)]

***

Expand All @@ -51,11 +51,11 @@ By default, indexes aren't unique: multiple rows are allowed to have the same va

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

[!code-csharp[Main](../../../samples/core/Modeling/DataAnnotations/IndexUnique.cs?name=IndexUnique&highlight=1)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/DataAnnotations/IndexUnique.cs?name=IndexUnique&highlight=1)]

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

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/IndexUnique.cs?name=IndexUnique&highlight=5)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/IndexUnique.cs?name=IndexUnique&highlight=5)]

***

Expand All @@ -69,11 +69,11 @@ You can set the name of the index created in the database:

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

[!code-csharp[Main](../../../samples/core/Modeling/DataAnnotations/IndexName.cs?name=IndexName&highlight=1)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/DataAnnotations/IndexName.cs?name=IndexName&highlight=1)]

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

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/IndexName.cs?name=IndexName&highlight=5)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/IndexName.cs?name=IndexName&highlight=5)]

***

Expand All @@ -83,16 +83,28 @@ Some relational databases allow you to specify a filtered or partial index. This

You can use the Fluent API to specify a filter on an index, provided as a SQL expression:

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/IndexFilter.cs?name=IndexFilter&highlight=5)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/IndexFilter.cs?name=IndexFilter&highlight=5)]

When using the SQL Server provider EF adds an `'IS NOT NULL'` filter for all nullable columns that are part of a unique index. To override this convention you can supply a `null` value.

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

## Included columns

Some relational databases allow you to configure a set of columns which get included in the index, but aren't part of its "key". This can significantly improve query performance when all columns in the query are included in the index either as key or nonkey columns, as the table itself doesn't need to be accessed. For more information on SQL Server included columns, [see the documentation](/sql/relational-databases/indexes/create-indexes-with-included-columns).

In the following example, the `Url` column is part of the index key, so any query filtering on that column can use the index. But in addition, queries accessing only the `Title` and `PublishedOn` columns will not need to access the table and will run more efficiently:

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/IndexInclude.cs?name=IndexInclude&highlight=5-9)]
[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/IndexInclude.cs?name=IndexInclude&highlight=5-9)]

## Check constraints

Check constraints are a standard relational feature that allows you to define a condition that must hold for all rows in a table; any attempt to insert or modify data that violates the constraint will fail. Check constraints are similar to non-null constraints (which prohibit nulls in a column) or to unique constraints (which prohibit duplicates), but allow arbitrary SQL expression to be defined.

You can use the Fluent API to specify a check constraint on a table, provided as a SQL expression:

[!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/CheckConstraint.cs?name=CheckConstraint&highlight=4)]

Multiple check constraints can be defined on the same table, each with their own name.

Note: some common check constraints can be configured via the community package [EFCore.CheckConstraints](https://github.com/efcore/EFCore.CheckConstraints).
4 changes: 2 additions & 2 deletions entity-framework/core/performance/efficient-querying.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Efficient Querying - EF Core
description: Performance guide for efficient querying using Entity Framework Core
author: roji
ms.date: 12/1/2020
ms.date: 10/1/2021
uid: core/performance/efficient-querying
---
# Efficient Querying
Expand All @@ -20,7 +20,7 @@ A good way to spot indexing issues is to first pinpoint a slow query, and then e
As a general rule, there isn't any special EF knowledge to using indexes or diagnosing performance issues related to them; general database knowledge related to indexes is just as relevant to EF applications as to applications not using EF. The following lists some general guidelines to keep in mind when using indexes:

* While indexes speed up queries, they also slow down updates since they need to be kept up-to-date. Avoid defining indexes which aren't needed, and consider using [index filters](xref:core/modeling/indexes#index-filter) to limit the index to a subset of the rows, thereby reducing this overhead.
* Composite indexes can speed up queries which filter on multiple columns, but they can also speed up queries which don't filter on all the index's columns - depending on ordering. For example, an index on columns A and B speed up queries filtering by A and B, as well as queries filtering only by A, but it does not speed up queries filtering over only by B.
* Composite indexes can speed up queries which filter on multiple columns, but they can also speed up queries which don't filter on all the index's columns - depending on ordering. For example, an index on columns A and B speeds up queries filtering by A and B as well as queries filtering only by A, but it does not speed up queries only filtering over B.
* If a query filters by an expression over a column (e.g. `price / 2`), a simple index cannot be used. However, you can define a [stored persisted column](xref:core/modeling/generated-properties#computed-columns) for your expression, and create an index over that. Some databases also support expression indexes, which can be directly used to speed up queries filtering by any expression.
* Different databases allow indexes to be configured in various ways, and in many cases EF Core providers expose these via the Fluent API. For example, the SQL Server provider allows you to configure whether an index is [clustered](xref:core/providers/sql-server/indexes#clustering), or set its [fill factor](xref:core/providers/sql-server/indexes#fill-factor). Consult your provider's documentation for more information.

Expand Down
2 changes: 1 addition & 1 deletion entity-framework/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
href: core/modeling/shadow-properties.md
- name: Relationships
href: core/modeling/relationships.md
- name: Indexes
- name: Indexes and constraints
href: core/modeling/indexes.md
- name: Inheritance
href: core/modeling/inheritance.md
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.DataAnnotations.Index
namespace EFModeling.IndexesAndConstraints.DataAnnotations.Index
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.DataAnnotations.IndexComposite
namespace EFModeling.IndexesAndConstraints.DataAnnotations.IndexComposite
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.Relational.IndexName
namespace EFModeling.IndexesAndConstraints.DataAnnotations.IndexName
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.DataAnnotations.IndexUnique
namespace EFModeling.IndexesAndConstraints.DataAnnotations.IndexUnique
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.IndexesAndConstraints.FluentAPI.CheckConstraint
{
internal class MyContext : DbContext
{
public DbSet<Product> Products { get; set; }

#region CheckConstraint
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasCheckConstraint("CK_Prices", "[Price] > [DiscountedPrice]");
}
#endregion
}

public class Product
{
public int Id { get; set; }
public decimal Price { get; set; }
public decimal DiscountedPrice { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.Index
namespace EFModeling.IndexesAndConstraints.FluentAPI.Index
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.IndexComposite
namespace EFModeling.IndexesAndConstraints.FluentAPI.IndexComposite
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.Relational.IndexFilter
namespace EFModeling.IndexesAndConstraints.FluentAPI.IndexFilter
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.Relational.IndexInclude
namespace EFModeling.IndexesAndConstraints.FluentAPI.IndexInclude
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.Relational.IndexName
namespace EFModeling.IndexesAndConstraints.FluentAPI.IndexName
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.Relational.IndexNoFilter
namespace EFModeling.IndexesAndConstraints.FluentAPI.IndexNoFilter
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.IndexUnique
namespace EFModeling.IndexesAndConstraints.FluentAPI.IndexUnique
{
internal class MyContext : DbContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.10" />
</ItemGroup>

</Project>
9 changes: 9 additions & 0 deletions samples/core/Modeling/IndexesAndConstraints/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace EFModeling.IndexesAndConstraints
{
internal class Program
{
private static void Main(string[] args)
{
}
}
}
7 changes: 7 additions & 0 deletions samples/core/Samples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewInEFCore6.Cosmos", "Misc
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompiledModels", "Miscellaneous\CompiledModels\CompiledModels.csproj", "{E6DC981D-4404-496E-972B-8DAC5D4A56F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IndexesAndConstraints", "Modeling\IndexesAndConstraints\IndexesAndConstraints.csproj", "{56F8DE05-6E33-4DB0-A779-70164B200289}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -437,6 +439,10 @@ Global
{E6DC981D-4404-496E-972B-8DAC5D4A56F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6DC981D-4404-496E-972B-8DAC5D4A56F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6DC981D-4404-496E-972B-8DAC5D4A56F6}.Release|Any CPU.Build.0 = Release|Any CPU
{56F8DE05-6E33-4DB0-A779-70164B200289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56F8DE05-6E33-4DB0-A779-70164B200289}.Debug|Any CPU.Build.0 = Debug|Any CPU
{56F8DE05-6E33-4DB0-A779-70164B200289}.Release|Any CPU.ActiveCfg = Release|Any CPU
{56F8DE05-6E33-4DB0-A779-70164B200289}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -503,6 +509,7 @@ Global
{DADCEB89-6242-4A40-A390-0D957E02D426} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{9614B4D9-08B7-4DA1-AF92-5B640C3C4E3D} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{E6DC981D-4404-496E-972B-8DAC5D4A56F6} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{56F8DE05-6E33-4DB0-A779-70164B200289} = {CA5046EC-C894-4535-8190-A31F75FDEB96}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {20C98D35-54EF-46A6-8F3B-1855C1AE4F70}
Expand Down