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

Update keyless entity types topic #1736

Merged
merged 1 commit into from
Sep 18, 2019
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
5 changes: 5 additions & 0 deletions .openpublishing.redirection.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@
"source_path": "entity-framework/core/extensions/llbl-gen-pro.md",
"redirect_url": "/ef/core/extensions/index",
"redirect_document_id": false
},
{
"source_path": "entity-framework/core/modeling/query-types.md",
"redirect_url": "/ef/core/modeling/keyless-entity-types",
"redirect_document_id": false
}
]
}
6 changes: 2 additions & 4 deletions entity-framework/core/managing-schemas/scaffolding.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,11 @@ Finally, the model is used to generate code. The corresponding entity type class

## What doesn't work

Not everything about a model can be represented using a database schema. For example, information about **inheritance hierarchies**, **owned types**, and **table splitting** are not present in the database schema. Because of this, these constructs will never be reverse engineered.
Not everything about a model can be represented using a database schema. For example, information about [**inheritance hierarchies**](../modeling/inheritance.md), [**owned types**](../modeling/owned-entities.md), and [**table splitting**](../modeling/table-splitting.md) are not present in the database schema. Because of this, these constructs will never be reverse engineered.

In addition, **some column types** may not be supported by the EF Core provider. These columns won't be included in the model.

EF Core requires every entity type to have a key. Tables, however, aren't required to specify a primary key. **Tables without a primary key** are currently not reverse engineered.

You can define **concurrency tokens** in an EF Core model to prevent two users from updating the same entity at the same time. Some databases have a special type to represent this type of column (for example, rowversion in SQL Server) in which case we can reverse engineer this information; however, other concurrency tokens will not be reverse engineered.
You can define [**concurrency tokens**](../modeling/concurrency.md), in an EF Core model to prevent two users from updating the same entity at the same time. Some databases have a special type to represent this type of column (for example, rowversion in SQL Server) in which case we can reverse engineer this information; however, other concurrency tokens will not be reverse engineered.

## Customizing the model

Expand Down
81 changes: 81 additions & 0 deletions entity-framework/core/modeling/keyless-entity-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: Keyless Entity Types - EF Core
author: AndriySvyryd
ms.author: ansvyryd
ms.date: 02/26/2018
ms.assetid: 9F4450C5-1A3F-4BB6-AC19-9FAC64292AAD
uid: core/modeling/keyless-entity-types
---
# Keyless Entity Types
> [!NOTE]
> This feature is new in EF Core 2.1. Prior to 3.0 they were known as Query Types

In addition to regular entity types, an EF Core model can contain _keyless entity types_, which can be used to carry out database queries against data that doesn't contain key values.

## Keyless entity types characteristics

Keyless entity types support many of the same mapping capabilities as regular entity types, like inheritance mapping and navigation properties. On relational stores, they can configure the target database objects and columns via fluent API methods or data annotations.

However, they are different from regular entity types in that they:

- Cannot have a key defined.
- Are never tracked for changes in the _DbContext_ and therefore are never inserted, updated or deleted on the database.
- Are never discovered by convention.
- Only support a subset of navigation mapping capabilities, specifically:
- They may never act as the principal end of a relationship.
- They may not have navigations to owned entities
- They can only contain reference navigation properties pointing to regular entities.
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved
- Entities cannot contain navigation properties to keyless entity types.
- Need to be configured with `.HasNoKey()` method call.
- May be mapped to a _defining query_. A defining query is a query declared in the model that acts as a data source for a keyless entity type.

## Usage scenarios

Some of the main usage scenarios for keyless entity types are:

- Serving as the return type for [raw SQL queries](xref:core/querying/raw-sql).
- Mapping to database views that do not contain a primary key.
- Mapping to tables that do not have a primary key defined.
- Mapping to queries defined in the model.

## Mapping to database objects

Mapping a keyless entity type to a database object is achieved using the `ToTable` or `ToView` fluent API. From the perspective of EF Core, the database object specified in this method is a _view_, meaning that it is treated as a read-only query source and cannot be the target of update, insert or delete operations. However, this does not mean that the database object is actually required to be a database view. It can alternatively be a database table that will be treated as read-only. Conversely, for regular entity types, EF Core assumes that a database object specified in the `ToTable` method can be treated as a _table_, meaning that it can be used as a query source but also targeted by update, delete and insert operations. In fact, you can specify the name of a database view in `ToTable` and everything should work fine as long as the view is configured to be updatable on the database.

> [!NOTE]
> `ToView` assumes that the object already exists in the database and it won't be created by migrations.

## Example

The following example shows how to use keyless entity types to query a database view.

> [!TIP]
> You can view this article's [sample](https://github.com/aspnet/EntityFramework.Docs/tree/master/samples/core/QueryTypes) on GitHub.

First, we define a simple Blog and Post model:

[!code-csharp[Main](../../../samples/core/KeylessEntityTypes/Program.cs#Entities)]

Next, we define a simple database view that will allow us to query the number of posts associated with each blog:

[!code-csharp[Main](../../../samples/core/KeylessEntityTypes/Program.cs#View)]

Next, we define a class to hold the result from the database view:

[!code-csharp[Main](../../../samples/core/KeylessEntityTypes/Program.cs#KeylessEntityType)]

Next, we configure the keyless entity type in _OnModelCreating_ using the `HasNoKey` API.
We use fluent configuration API to configure the mapping for the keyless entity type:

[!code-csharp[Main](../../../samples/core/KeylessEntityTypes/Program.cs#Configuration)]

Next, we configure the `DbContext` to include the `DbSet<T>`:

[!code-csharp[Main](../../../samples/core/KeylessEntityTypes/Program.cs#DbSet)]

Finally, we can query the database view in the standard way:

[!code-csharp[Main](../../../samples/core/KeylessEntityTypes/Program.cs#Query)]

> [!TIP]
> Note we have also defined a context level query property (DbSet) to act as a root for queries against this type.
81 changes: 0 additions & 81 deletions entity-framework/core/modeling/query-types.md

This file was deleted.

2 changes: 1 addition & 1 deletion entity-framework/core/querying/raw-sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ uid: core/querying/raw-sql
---
# Raw SQL Queries

Entity Framework Core allows you to drop down to raw SQL queries when working with a relational database. This can be useful if the query you want to perform can't be expressed using LINQ, or if using a LINQ query is resulting in inefficient SQL queries. Raw SQL queries can return entity types or, starting with EF Core 2.1, [query types](xref:core/modeling/query-types) that are part of your model.
Entity Framework Core allows you to drop down to raw SQL queries when working with a relational database. This can be useful if the query you want to perform can't be expressed using LINQ, or if using a LINQ query is resulting in inefficient SQL queries. Raw SQL queries can return entity types or, starting with EF Core 2.1, [keyless entity types](xref:core/modeling/keyless-entity-types) that are part of your model.

> [!TIP]
> You can view this article's [sample](https://github.com/aspnet/EntityFramework.Docs/tree/master/samples/core/Querying) on GitHub.
Expand Down
2 changes: 1 addition & 1 deletion entity-framework/core/what-is-new/ef-core-2.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ An EF Core model can now include query types. Unlike entity types, query types d
- Mapping to queries defined in the model
- Serving as the return type for `FromSql()` queries

Read the [section on query types](xref:core/modeling/query-types) for more information about this topic.
Read the [section on query types](xref:core/modeling/keyless-entity-types) for more information about this topic.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is keeping link title as query types here intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in 2.1 they were query types


## Include for derived types
It will be now possible to specify navigation properties only defined on derived types when writing expressions for the `Include` method. For the strongly typed version of `Include`, we support using either an explicit cast or the `as` operator. We also now support referencing the names of navigation property defined on derived types in the string version of `Include`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ This change is introduced in EF Core 3.0-preview 3.

**Old behavior**

Before EF Core 3.0, [query types](xref:core/modeling/query-types) were a means to query data that doesn't define a primary key in a structured way.
Before EF Core 3.0, [query types](xref:core/modeling/keyless-entity-types) were a means to query data that doesn't define a primary key in a structured way.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

That is, a query type was used for mapping entity types without keys (more likely from a view, but possibly from a table) while a regular entity type was used when a key was available (more likely from a table, but possibly from a view).

**New behavior**
Expand Down
4 changes: 2 additions & 2 deletions entity-framework/efcore-and-ef6/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The EF Core column indicates the product version in which the feature first appe
| Basic class mapping | Yes | 1.0 |
| Constructors with parameters | | 2.1 |
| Property value conversions | | 2.1 |
| Mapped types with no keys (query types) | | 2.1 |
| Mapped types with no keys | | 2.1 |
| Conventions | Yes | 1.0 |
| Custom conventions | Yes | 1.0 (partial) |
| Data annotations | Yes | 1.0 |
Expand Down Expand Up @@ -79,7 +79,7 @@ The EF Core column indicates the product version in which the feature first appe
| Loading related data: Lazy | Yes | 2.1 |
| Loading related data: Explicit | Yes | 1.1 |
| Raw SQL queries: Entity types | Yes | 1.0 |
| Raw SQL queries: Non-entity types (query types) | Yes | 2.1 |
| Raw SQL queries: Keyless entity types | Yes | 2.1 |
| Raw SQL queries: Composing with LINQ | | 1.0 |
| Explicitly compiled queries | Poor | 2.0 |
| Text-based query language (Entity SQL) | Yes | |
Expand Down
2 changes: 1 addition & 1 deletion entity-framework/toc.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
#### [Entity Type Constructors](core/modeling/constructors.md)
#### [Table Splitting](core/modeling/table-splitting.md)
#### [Owned Entity Types](core/modeling/owned-entities.md)
#### [Query Types](core/modeling/query-types.md)
#### [Keyless Entity Types](core/modeling/keyless-entity-types.md)
#### [Alternating models with same DbContext](core/modeling/dynamic-model.md)
#### [Spatial Data (GIS)](core/modeling/spatial.md)
#### [Relational Database Modeling](core/modeling/relational/index.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>netcoreapp3.0</TargetFramework>
<RootNamespace>Samples</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0-*" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.0-*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0-rc1.19456.14" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0-rc1.19456.10" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private static void SetupDatabase()
db.SaveChanges();

#region View
db.Database.ExecuteSqlCommand(
db.Database.ExecuteSqlRaw(
@"CREATE VIEW View_BlogPostCounts AS
SELECT b.Name, Count(p.PostId) as PostCount
FROM Blogs b
Expand All @@ -93,29 +93,33 @@ FROM Blogs b
public class BloggingContext : DbContext
{
private static readonly ILoggerFactory _loggerFactory
= new LoggerFactory().AddConsole((s, l) => l == LogLevel.Information && !s.EndsWith("Connection"));
= LoggerFactory.Create(builder => builder.AddConsole().AddFilter((c, l) => l == LogLevel.Information && !c.EndsWith("Connection")));

public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }

#region DbQuery
public DbQuery<BlogPostsCount> BlogPostCounts { get; set; }
#region DbSet
public DbSet<BlogPostsCount> BlogPostCounts { get; set; }
#endregion

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Sample.QueryTypes;Trusted_Connection=True;ConnectRetryCount=0;")
@"Server=(localdb)\mssqllocaldb;Database=Sample.KeylessEntityTypes;Trusted_Connection=True;ConnectRetryCount=0;")
.UseLoggerFactory(_loggerFactory);
}

#region Configuration
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Query<BlogPostsCount>().ToView("View_BlogPostCounts")
.Property(v => v.BlogName).HasColumnName("Name");
.Entity<BlogPostsCount>(eb =>
{
eb.HasNoKey();
eb.ToView("View_BlogPostCounts");
eb.Property(v => v.BlogName).HasColumnName("Name");
});
}
#endregion
}
Expand All @@ -138,7 +142,7 @@ public class Post
}
#endregion

#region QueryType
#region KeylessEntityType
public class BlogPostsCount
{
public string BlogName { get; set; }
Expand Down
5 changes: 5 additions & 0 deletions samples/core/KeylessEntityTypes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Keyless Entity Types

This sample demonstrates Keyless Entity Types. A simple Blog and Post model is created and a Keyless Entity Type is used to query a database view.


5 changes: 0 additions & 5 deletions samples/core/QueryTypes/README.md

This file was deleted.

2 changes: 1 addition & 1 deletion samples/core/Samples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompiledQueries", "Compiled
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbContextPooling", "DbContextPooling\DbContextPooling.csproj", "{EFA3A7DD-F76C-4DA9-A657-D08E78E7E397}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QueryTypes", "QueryTypes\QueryTypes.csproj", "{BB293879-4741-4D7A-87E8-3B9727B43A19}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KeylessEntityTypes", "KeylessEntityTypes\KeylessEntityTypes.csproj", "{BB293879-4741-4D7A-87E8-3B9727B43A19}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TableSplitting", "Modeling\TableSplitting\TableSplitting.csproj", "{63685B9A-1233-4B44-AAC1-8DDD4B16B65D}"
EndProject
Expand Down