Net Core:通用存储库主 ID 实体框架中的关键性能 [英] Net Core: Generic Repository Primary Id Key Performance in Entity Framework

查看:40
本文介绍了Net Core:通用存储库主 ID 实体框架中的关键性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在审查通用存储库模式中的两种不同方法.目前,想要将主键映射到 Id.这样做的目的是映射到使用 Id 的通用存储库接口.下面提供了两种解决方案.

.FindPrimaryKey().Properties 对性能有何影响.在尝试查找主键时,它是否会导致数据库表上的模式锁定?它会导致任何应用程序缓慢吗?

它与部分类方法解决方案 2 的性能相比如何?哪个选项在性能方面更好?

注意:架构师要求在工作场所使用存储库模式,因此要实施它.知道围绕这个问题有争论,但不是我的呼吁.

脚手架模型示例:

命名空间数据测试{公共部分类属性{公共 int 属性 { 获取;放;}公共 int DocumentId { 获取;放;}公共字符串地址{获取;放;}}}

所有表的示例通用基础存储库:

 public T Get(int id){返回 Table.Find(id);}公共异步任务<T>GetAsync(int id){返回等待 Table.FindAsync(id);}public T Single(Expression<Func<T, bool>>谓词){返回 All.Single(谓词);}公共异步任务<T>SingleAsync(Expression<Func<T, bool>>谓词){返回等待 All.SingleAsync(谓词);}公共 T FirstOrDefault(int id){返回 All.FirstOrDefault(CreateEqualityExpressionForId(id));}

方案一:FindPrimaryKey()

使用实体框架的 C# 通用存储库

使用 EF FindPrimaryKey()

var idName = _context.Model.FindEntityType(typeof(TEntity)).FindPrimaryKey().Properties.Single().Name;

解决方案 2:部分类映射

Net Core:为所有表自动代码生成创建通用存储库接口 Id 映射

公共部分类属性:IEntity{[未映射]public int Id { get =>属性编号;设置 =>属性 ID = 值;}}

解决方案

关于第一种方法(使用 EF Core 元数据服务):

首先,EF Core 是 ORM(Object Relational Mapper),这里最重要的是 Mapper.

其次,它使用所谓的基于代码的模型,这意味着所有映射都是由代码提供的,而不是实际的数据库(即使模型是通过对现有数据库进行逆向工程创建的).

简而言之,EF Core 在运行时创建了一个内存数据结构,其中包含有关类和属性的信息(元数据)以及它们到数据库表、列和关系的映射.所有这些信息都基于纯代码模型——实体类、约定、数据注释和流畅的配置.

所有 EF Core 运行时行为都基于该元数据模型.EF Core 在构建查询、将查询结果映射到对象、链接导航属性、生成创建/更新/删除命令及其执行顺序、在获取真正的自动生成的主要键值后更新临时 FK 属性值等时在内部使用它.

因此,元数据模型和发现服务(方法)使用优化的数据结构并且(必须)非常高效.同样,不涉及数据库操作.

所以第一种方法非常有效.与实际的查询构建、执行和具体化相比,通过元数据服务获取 PK 属性 名称对性能的影响可以忽略不计.

第一种方法的性能也类似于您在另一种方法中使用的 EF Core Find 方法.请注意,在调用 Find 方法时,您只传递 PK 值而不是属性.所以方法实现应该知道如何构建 Where 表达式,对吗?它在内部所做的与建议的代码段非常相似.

<小时>

关于第二种方法:

它根本没有可比性,因为它不起作用.可以使用基类/接口,但前提是映射了实际的属性名称 - 就像所有类都具有 Id 属性,并且映射到数据库中不同的列名称使用 [Column] 数据注释或 HasColumnName fluent API 的表格.

在您的示例中,Id 属性是 [NotMapped](被忽略).这意味着 EF Core 无法映射到表列.您通过代码(属性 getter/setter)将它映射到另一个属性并不重要.EF Core 不是(反)编译器,它看不到您的代码,因此无法将使用此类属性的 LINQ 查询转换为 SQL.

在 EF Core 2.x 中导致 client评估(非常低效,读取整个表并在内存中应用过滤器),或者如果客户端评估是 配置为这样做.而在 EF Core 3.0+ 它永远是个例外.

因此,如果您不删除像 PropertyIdma​​p 属性 Id 之类的属性(这对于数据库优先"来说很难模型),应该避免第二种方法".即使您可以映射实际的 Id 属性,您所节省的时间也只是几毫秒.再说一次,在使用 Find 时,您不必担心性能,何必为使用相同(或相似)方法的方法而烦恼.

We are reviewing two different methods in generic repository patterns. Currently, want to map primary keys to Ids. The purpose of this is to map to the Generic Repository Interface which utilizes Id. Two solutions are provided below.

What are performance implications of .FindPrimaryKey().Properties. Does it cause a schema lock on database table in trying to find the primary key? Does it cause any application slowness?

How does it compare in performance vs Partial Class Method Solution 2? What option is better performance-wise?

Note: Architects demand the use of repository pattern at the workplace, so implementing it. Know there is debate surrounding this issue, but not my call.

Scaffolded Model Example:

namespace Datatest
{
    public partial class Property
    {
        public int Property { get; set; }
        public int DocumentId { get; set; }
        public string Address { get; set; }
    }
}

Sample Generic Base Repository for all tables:

    public T Get(int id)
    {
        return Table.Find(id);
    }
    public async Task<T> GetAsync(int id)
    {
        return await Table.FindAsync(id);
    }
    public T Single(Expression<Func<T, bool>> predicate)
    {
        return All.Single(predicate);
    }
    public async Task<T> SingleAsync(Expression<Func<T, bool>> predicate)
    {
        return await All.SingleAsync(predicate);
    }
    public T FirstOrDefault(int id)
    {
        return All.FirstOrDefault(CreateEqualityExpressionForId(id));
    }

Solution 1: FindPrimaryKey()

Generic Repository in C# Using Entity Framework

use EF FindPrimaryKey()

var idName = _context.Model.FindEntityType(typeof(TEntity))
        .FindPrimaryKey().Properties.Single().Name;

Solution 2: Partial classes Mapping

Net Core: Create Generic Repository Interface Id Mapping for All Tables Auto Code Generation

public partial class Property: IEntity
{
    [NotMapped]
    public int Id { get => PropertyId; set => PropertyId = value; }
}

解决方案

Regarding the first approach (using EF Core metadata services):

First, EF Core is ORM (Object Relational Mapper), with most important here is Mapper.

Second, it uses the so called code based model, which means all the mappings are provided by code and not the actual database (even though the model is created by reverse engineering of an existing database).

In simple words, EF Core creates at runtime a memory data structure containing the information (metadata) about classes and properties, and their mappings to database tables, columns and relationships. All that information is based on pure code model - the entity classes, conventions, data annotations and fluent configuration.

All EF Core runtime behaviors are based on that metadata model. EF Core uses it internally when building queries, mapping the query results to objects, linking navigation properties, generating create/update/delete commands and their order of execution, updating temporary FK property values after getting the real autogenerated principal key values etc.

Hence the metadata model and discovering services (methods) use optimized data structures and are (has to be) quite efficient. And again, no database operations are involved.

So the first approach is quite efficient. The performance impact of obtaining the PK property name via metadata service is negligible compared to actual query building, execution and materialization.

Also the performance of the first approach is similar to EF Core Find method which you are using in another method. Note that when calling Find method you just pass the PK value(s) and not the properties. So the method implementation should somehow know how to build the Where expression, right? And what it does internally is very similar to the suggested snippet.


Regarding the second approach:

It's simply not comparable because it doesn't work. It's possible to use base class/interface, but only if the actual property name is mapped - like all classes have Id property, and it's mapped to different column name in the database tables using [Column] data annotation or HasColumnName fluent API.

In your example, the Id property is [NotMapped] (ignored). Which means EF Core cannot map to the table column. The fact that your are mapping it to another property via code (property getter/setter) doesn't matter. EF Core is not a (de)compiler, it can't see your code, hence cannot translate a LINQ query using such properties to SQL.

Which in EF Core 2.x leads to either client evaluation (very inefficient, reading to whole table and applying the filter in memory), or exception if client evaluation is configured to do so. And in EF Core 3.0+ it will always be an exception.

So in case you don't remove properties like PropertyId and map the property Id (which would be hard with "database first" models), the second "approach" should be avoided. And even if you can map the actual Id property, all you'll save would be a few milliseconds. And again, when using Find you don't bother about performance, why bother with methods that uses the same (or similar) approach.

这篇关于Net Core:通用存储库主 ID 实体框架中的关键性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆