diff --git a/entity-framework/core/querying/filters.md b/entity-framework/core/querying/filters.md index f88ca8f7e8..6abfa4e5b0 100644 --- a/entity-framework/core/querying/filters.md +++ b/entity-framework/core/querying/filters.md @@ -10,23 +10,23 @@ uid: core/querying/filters > [!NOTE] > This feature was introduced in EF Core 2.0. -Global query filters are LINQ query predicates (a boolean expression typically passed to the LINQ *Where* query operator) applied to Entity Types in the metadata model (usually in *OnModelCreating*). Such filters are automatically applied to any LINQ queries involving those Entity Types, including Entity Types referenced indirectly, such as through the use of Include or direct navigation property references. Some common applications of this feature are: +Global query filters are LINQ query predicates applied to Entity Types in the metadata model (usually in *OnModelCreating*). A query predicate is a boolean expression typically passed to the LINQ *Where* query operator. EF Core applies such filters automatically to any LINQ queries involving those Entity Types. EF Core also applies them to Entity Types, referenced indirectly through use of Include or navigation property. Some common applications of this feature are: * **Soft delete** - An Entity Type defines an *IsDeleted* property. * **Multi-tenancy** - An Entity Type defines a *TenantId* property. ## Example -The following example shows how to use Global Query Filters to implement soft-delete and multi-tenancy query behaviors in a simple blogging model. +The following example shows how to use Global Query Filters to implement multi-tenancy and soft-delete query behaviors in a simple blogging model. > [!TIP] -> You can view a [multi-tenancy sample](https://github.com/dotnet/EntityFramework.Docs/tree/master/samples/core/QueryFilters) and [samples using navigations](https://github.com/dotnet/EntityFramework.Docs/tree/master/samples/core/QueryFiltersNavigations) on GitHub. +> You can view a [multi-tenancy sample](https://github.com/dotnet/EntityFramework.Docs/tree/master/samples/core/QueryFilters) and [samples using navigations](https://github.com/dotnet/EntityFramework.Docs/tree/master/samples/core/QueryFiltersNavigations) on GitHub. First, define the entities: [!code-csharp[Main](../../../samples/core/QueryFilters/Program.cs#Entities)] -Note the declaration of a _tenantId_ field on the _Blog_ entity. This will be used to associate each Blog instance with a specific tenant. Also defined is an _IsDeleted_ property on the _Post_ entity type. This is used to keep track of whether a _Post_ instance has been "soft-deleted". That is, the instance is marked as deleted without physically removing the underlying data. +Note the declaration of a _tenantId_ field on the _Blog_ entity. This field will be used to associate each Blog instance with a specific tenant. Also defined is an _IsDeleted_ property on the _Post_ entity type. This property is used to keep track of whether a _Post_ instance has been "soft-deleted". That is, the instance is marked as deleted without physically removing the underlying data. Next, configure the query filters in _OnModelCreating_ using the `HasQueryFilter` API. @@ -42,17 +42,17 @@ The predicate expressions passed to the _HasQueryFilter_ calls will now automati ## Use of navigations -Navigations can be used when defining global query filters. They are applied recursively - when navigations used in query filters are translated, query filters defined on referenced entities are also applied, potentially adding more navigations. +You can also use navigations in defining global query filters. Using navigations in query filter will cause query filters to be applied recursively. When EF Core expands navigations used in query filters, it will also apply query filters defined on referenced entities. > [!NOTE] -> Currently EF Core does not detect cycles in global query filter definitions, so you should be careful when defining them. If specified incorrectly, this could lead to infinite loops during query translation. +> Currently EF Core does not detect cycles in global query filter definitions, so you should be careful when defining them. If specified incorrectly, cycles could lead to infinite loops during query translation. ## Accessing entity with query filter using required navigation > [!CAUTION] -> Using required navigation to access entity which has global query filter defined may lead to unexpected results. +> Using required navigation to access entity which has global query filter defined may lead to unexpected results. -Required navigation expects the related entity to always be present. If required related entity is filtered out by the query filter, the parent entity could end up in unexpected state. This may result in returning fewer elements than expected. +Required navigation expects the related entity to always be present. If necessary related entity is filtered out by the query filter, the parent entity wouldn't be in result either. So you may get fewer elements than expected in result. To illustrate the problem, we can use the `Blog` and `Post` entities specified above and the following _OnModelCreating_ method: @@ -72,7 +72,7 @@ The problem can be observed when executing two queries: [!code-csharp[Main](../../../samples/core/QueryFiltersNavigations/Program.cs#Queries)] -With this setup, the first query returns all 6 `Post`s, however the second query only returns 3. This happens because _Include_ method in the second query loads the related `Blog` entities. Since the navigation between `Blog` and `Post` is required, EF Core uses `INNER JOIN` when constructing the query: +With above setup, the first query returns all 6 `Post`s, however the second query only returns 3. This mismatch happens because _Include_ method in the second query loads the related `Blog` entities. Since the navigation between `Blog` and `Post` is required, EF Core uses `INNER JOIN` when constructing the query: ```SQL SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[IsDeleted], [p].[Title], [t].[BlogId], [t].[Name], [t].[Url] @@ -84,9 +84,9 @@ INNER JOIN ( ) AS [t] ON [p].[BlogId] = [t].[BlogId] ``` -Use of the `INNER JOIN` filters out all `Post`s whose related `Blog`s have been removed by a global query filter. +Use of the `INNER JOIN` filters out all `Post`s whose related `Blog`s have been removed by a global query filter. -It can be addressed by using optional navigation instead of required. +It can be addressed by using optional navigation instead of required. This way the first query stays the same as before, however the second query will now generate `LEFT JOIN` and return 6 results. ```csharp @@ -98,7 +98,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) ``` Alternative approach is to specify consistent filters on both `Blog` and `Post` entities. -This way matching filters are applied to both `Blog` and `Post`. `Post`s that could end up in unexpected state are removed and both queries return 3 results. +This way matching filters are applied to both `Blog` and `Post`. `Post`s that could end up in unexpected state are removed and both queries return 3 results. ```csharp protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/entity-framework/core/querying/how-query-works.md b/entity-framework/core/querying/how-query-works.md index 4f6c17abbd..d2e83cfeab 100644 --- a/entity-framework/core/querying/how-query-works.md +++ b/entity-framework/core/querying/how-query-works.md @@ -13,28 +13,28 @@ Entity Framework Core uses Language Integrated Query (LINQ) to query data from t ## The life of a query -The following is a high level overview of the process each query goes through. +The following description is a high-level overview of the process each query goes through. 1. The LINQ query is processed by Entity Framework Core to build a representation that is ready to be processed by the database provider 1. The result is cached so that this processing does not need to be done every time the query is executed 2. The result is passed to the database provider 1. The database provider identifies which parts of the query can be evaluated in the database - 2. These parts of the query are translated to database specific query language (for example, SQL for a relational database) + 2. These parts of the query are translated to database-specific query language (for example, SQL for a relational database) 3. A query is sent to the database and the result set returned (results are values from the database, not entity instances) 3. For each item in the result set - 1. If this is a tracking query, EF checks if the data represents an entity already in the change tracker for the context instance + 1. If the query is a tracking query, EF checks if the data represents an entity already in the change tracker for the context instance * If so, the existing entity is returned - * If not, a new entity is created, change tracking is setup, and the new entity is returned - 2. If this is a no-tracking query, then a new entity is always created and returned + * If not, a new entity is created, change tracking is set up, and the new entity is returned + 2. If the query is a no-tracking query, then a new entity is always created and returned ## When queries are executed -When you call LINQ operators, you are simply building up an in-memory representation of the query. The query is only sent to the database when the results are consumed. +When you call LINQ operators, you're simply building up an in-memory representation of the query. The query is only sent to the database when the results are consumed. The most common operations that result in the query being sent to the database are: * Iterating the results in a `for` loop -* Using an operator such as `ToList`, `ToArray`, `Single`, `Count` or the equivalent async overloads +* Using an operator such as `ToList`, `ToArray`, `Single`, `Count`, or the equivalent async overloads > [!WARNING] > **Always validate user input:** While EF Core protects against SQL injection attacks by using parameters and escaping literals in queries, it does not validate inputs. Appropriate validation, per the application's requirements, should be performed before values from un-trusted sources are used in LINQ queries, assigned to entity properties, or passed to other EF Core APIs. This includes any user input used to dynamically construct queries. Even when using LINQ, if you are accepting user input to build expressions, you need to make sure that only intended expressions can be constructed. diff --git a/entity-framework/core/querying/related-data.md b/entity-framework/core/querying/related-data.md index d3f69befc6..ea37d4a557 100644 --- a/entity-framework/core/querying/related-data.md +++ b/entity-framework/core/querying/related-data.md @@ -41,11 +41,11 @@ You can chain multiple calls to `ThenInclude` to continue including further leve [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#MultipleThenIncludes)] -You can combine all of this to include related data from multiple levels and multiple roots in the same query. +You can combine all of the calls to include related data from multiple levels and multiple roots in the same query. [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#IncludeTree)] -You may want to include multiple related entities for one of the entities that is being included. For example, when querying `Blogs`, you include `Posts` and then want to include both the `Author` and `Tags` of the `Posts`. To do this, you need to specify each include path starting at the root. For example, `Blog -> Posts -> Author` and `Blog -> Posts -> Tags`. This does not mean you will get redundant joins; in most cases, EF will consolidate the joins when generating SQL. +You may want to include multiple related entities for one of the entities that is being included. For example, when querying `Blogs`, you include `Posts` and then want to include both the `Author` and `Tags` of the `Posts`. To include both, you need to specify each include path starting at the root. For example, `Blog -> Posts -> Author` and `Blog -> Posts -> Tags`. It doesn't mean you'll get redundant joins; in most cases, EF will combine the joins when generating SQL. [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#MultipleLeafIncludes)] @@ -65,11 +65,11 @@ ORDER BY [b].[BlogId], [p].[PostId] If a typical blog has multiple related posts, rows for these posts will duplicate the blog's information, leading to the so-called "cartesian explosion" problem. As more one-to-many relationships are loaded, the amount of duplicated data may grow and adversely affect the performance of your application. -EF allows you to specify that a given LINQ query should be *split* into multiple SQL queries. Instead of JOINs, split queries perform an additional SQL query for each included one-to-many navigation: +EF allows you to specify that a given LINQ query should be *split* into multiple SQL queries. Instead of JOINs, split queries generate an additional SQL query for each included one-to-many navigation: [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs?name=AsSplitQuery&highlight=5)] -This will produce the following SQL: +It will produce the following SQL: ```sql SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url] @@ -82,11 +82,11 @@ INNER JOIN [Post] AS [p] ON [b].[BlogId] = [p].[BlogId] ORDER BY [b].[BlogId] ``` -While this avoids the performance issues associated with JOINs and cartesian explosion, it also has some drawbacks: +While split query avoids the performance issues associated with JOINs and cartesian explosion, it also has some drawbacks: -* While most databases guarantee data consistency for single queries, no such guarantees exist for multiple queries. This means that if the database is being updated concurrently as your queries are being executed, resulting data may not be consistent. This may be mitigated by wrapping the queries in a serializable or snapshot transaction, although this may create performance issues of its own. Consult your database's documentation for more details. -* Each query currently implies an additional network roundtrip to your database; this can degrade performance, especially where latency to the database is high (e.g. cloud services). EF Core will improve this in the future by batching the queries into a single roundtrip. -* While some databases allow consuming the results of multiple queries at the same time (SQL Server with MARS, Sqlite), most allow only a single query to be active at any given point. This means that all results from earlier queries must be buffered in your application's memory before executing later queries, increasing your memory requirements in a potentially significant way. +* While most databases guarantee data consistency for single queries, no such guarantees exist for multiple queries. If the database is updated concurrently when executing your queries, resulting data may not be consistent. You can mitigate it by wrapping the queries in a serializable or snapshot transaction, although doing so may create performance issues of its own. For more information, see your database's documentation. +* Each query currently implies an additional network roundtrip to your database. Multiple network roundtrip can degrade performance, especially where latency to the database is high (for example, cloud services). +* While some databases allow consuming the results of multiple queries at the same time (SQL Server with MARS, Sqlite), most allow only a single query to be active at any given point. So all results from earlier queries must be buffered in your application's memory before executing later queries, which leads to increased memory requirements. Unfortunately, there isn't one strategy for loading related entities that fits all scenarios. Carefully consider the advantages and disadvantages of single and split queries, and select the one that fits your needs. @@ -110,11 +110,11 @@ Such operations should be applied on the collection navigation in the lambda pas [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#FilteredInclude)] -Each included navigation allows only one unique set of filter operations. In cases where multiple Include operations are applied for a given collection navigation (`blog.Posts` in the examples below), filter operations can only be specified on one of them: +Each included navigation allows only one unique set of filter operations. In cases where multiple Include operations are applied for a given collection navigation (`blog.Posts` in the examples below), filter operations can only be specified on one of them: [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#MultipleLeafIncludesFiltered1)] -Alternatively, identical operations can be applied for each navigation that is included multiple times: +Instead, identical operations can be applied for each navigation that is included multiple times: [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#MultipleLeafIncludesFiltered2)] @@ -132,7 +132,7 @@ var filtered = context.Customers.Include(c => c.Orders.Where(o => o.Id > 5000)). ### Include on derived types -You can include related data from navigations defined only on a derived type using `Include` and `ThenInclude`. +You can include related data from navigation defined only on a derived type using `Include` and `ThenInclude`. Given the following model: @@ -194,13 +194,13 @@ You can explicitly load a navigation property via the `DbContext.Entry(...)` API [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#Eager)] -You can also explicitly load a navigation property by executing a separate query that returns the related entities. If change tracking is enabled, then when loading an entity, EF Core will automatically set the navigation properties of the newly-loaded entitiy to refer to any entities already loaded, and set the navigation properties of the already-loaded entities to refer to the newly-loaded entity. +You can also explicitly load a navigation property by executing a separate query that returns the related entities. If change tracking is enabled, then when query materializes an entity, EF Core will automatically set the navigation properties of the newly loaded entity to refer to any entities already loaded, and set the navigation properties of the already-loaded entities to refer to the newly loaded entity. ### Querying related entities You can also get a LINQ query that represents the contents of a navigation property. -This allows you to do things such as running an aggregate operator over the related entities without loading them into memory. +It allows you to apply additional operators over the query. Foe example applying an aggregate operator over the related entities without loading them into memory. [!code-csharp[Main](../../../samples/core/Querying/RelatedData/Sample.cs#NavQueryAggregate)] @@ -305,7 +305,7 @@ public class Post } ``` -This doesn't require entity types to be inherited from or navigation properties to be virtual, and allows entity instances created with `new` to lazy-load once attached to a context. However, it requires a reference to the `ILazyLoader` service, which is defined in the [Microsoft.EntityFrameworkCore.Abstractions](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Abstractions/) package. This package contains a minimal set of types so that there is very little impact in depending on it. However, to completely avoid depending on any EF Core packages in the entity types, it is possible to inject the `ILazyLoader.Load` method as a delegate. For example: +This method doesn't require entity types to be inherited from or navigation properties to be virtual, and allows entity instances created with `new` to lazy-load once attached to a context. However, it requires a reference to the `ILazyLoader` service, which is defined in the [Microsoft.EntityFrameworkCore.Abstractions](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Abstractions/) package. This package contains a minimal set of types so that there is little impact in depending on it. However, to completely avoid depending on any EF Core packages in the entity types, it's possible to inject the `ILazyLoader.Load` method as a delegate. For example: ```csharp public class Blog @@ -384,13 +384,13 @@ public static class PocoLoadingExtensions ## Related data and serialization -Because EF Core will automatically fix-up navigation properties, you can end up with cycles in your object graph. For example, loading a blog and its related posts will result in a blog object that references a collection of posts. Each of those posts will have a reference back to the blog. +Because EF Core automatically does fix-up of navigation properties, you can end up with cycles in your object graph. For example, loading a blog and its related posts will result in a blog object that references a collection of posts. Each of those posts will have a reference back to the blog. -Some serialization frameworks do not allow such cycles. For example, Json.NET will throw the following exception if a cycle is encountered. +Some serialization frameworks don't allow such cycles. For example, Json.NET will throw the following exception if a cycle is found. > Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'Blog' with type 'MyApplication.Models.Blog'. -If you are using ASP.NET Core, you can configure Json.NET to ignore cycles that it finds in the object graph. This is done in the `ConfigureServices(...)` method in `Startup.cs`. +If you're using ASP.NET Core, you can configure Json.NET to ignore cycles that it finds in the object graph. This configuration is done in the `ConfigureServices(...)` method in `Startup.cs`. ```csharp public void ConfigureServices(IServiceCollection services) diff --git a/entity-framework/core/querying/tracking.md b/entity-framework/core/querying/tracking.md index c0a1121055..653f4fdcfc 100644 --- a/entity-framework/core/querying/tracking.md +++ b/entity-framework/core/querying/tracking.md @@ -1,6 +1,6 @@ --- title: Tracking vs. No-Tracking Queries - EF Core -description: Informationn tracking and no-tracking queries in Entity Framework Core +description: Information on tracking and no-tracking queries in Entity Framework Core author: smitpatel ms.date: 10/10/2019 ms.assetid: e17e060c-929f-4180-8883-40c438fbcc01