网络核心:实体框架中通用存储库主ID的关键性能

时间:2019-08-07 04:19:09

标签: c# entity-framework asp.net-core .net-core entity-framework-core

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

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

与部分类方法解决方案2相比,它的性能如何? 哪种方法在性能上更好?

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

脚手架模型示例:

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

所有表的样本通用基础存储库:

    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));
    }

解决方案1:FindPrimaryKey()

Generic Repository in C# Using Entity Framework

使用EF FindPrimaryKey()

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

解决方案2:局部类映射

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; }
}

1 个答案:

答案 0 :(得分:4)

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

首先,EF Core是ORM(对象关系映射器),其中最重要的是 Mapper

第二,它使用所谓的基于代码的模型,这意味着所有映射均由代码而非实际数据库提供(即使该模型是通过对现有数据库进行反向工程创建的)

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

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

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

因此第一种方法非常有效。与实际查询的建立,执行和实现相比,通过元数据服务获得PK 属性名称对性能的影响可以忽略不计。

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


关于第二种方法:

这根本不具有可比性,因为它不起作用。可以使用基类/接口,但前提是必须映射实际的属性名-就像所有类都具有Id属性一样,并且可以使用{将其映射到数据库表中的其他列名 {1}}数据注释或[Column]流利的API。

在您的示例中,HasColumnName属性为Id(忽略)。这意味着EF Core无法映射到表列。您通过代码(属性获取器/设置器)将其映射到另一个属性的事实并不重要。 EF Core是不是的(反)编译器,它看不到您的代码,因此无法将使用此类属性的LINQ查询转换为SQL。

在EF Core 2.x中,哪个导致client evaluation(效率很低,读取整个表并在内存中应用过滤器),或者导致客户端评估为configured to do so的异常。而在EF Core 3.0+ it will always be an exception中。

因此,如果您不删除[NotMapped] map 这样的属性PropertyId(对于“数据库优先”的模型来说很难),第二个“方法”。并且即使您可以映射实际的Id属性,您节省的时间也只有几毫秒。再说一次,当使用Id时,您不必担心性能,为什么还要麻烦使用相同(或相似)方法的方法。