如何高效地将 EF linq 查询迁移到 Dapper?

How to efficiently migrate EF linq queries to Dapper?

我正在尝试将 EF 迁移到 Dapper,我正在寻找一种更好、更有效的方法来迁移现有的 linq 表达式"IQueryable"以使用 Dapper。

例如:

public class MyDbContext : DbContext
{
    public DbSet<MyEntity> MyEntity { get; set; }
    +20 more entities..
}

// Inside repository
using (var context = new MyDbContext())
{
     context.MyEntity.Where( x => x.Id == 1) // How can I easily migrate this linq to Dapper?
}

以上代码只是我尝试迁移的一个简单示例。其中一些查询既简单又复杂。目前,我在 MyDbContext 中有 20 多个存储库和 20 多个 DbSet,它们在存储库中使用了这种方法。

我在网上搜索了一下,没有找到更好的方法。到目前为止,唯一的方法是将linq 一个一个地转换成查询字符串并在Dapper 中使用它。这是可行的,但繁琐且需要付出巨大的努力。性能是我最关心的问题,所以我要迁移到 Dapper。

有没有人有比我现在想的更好的方法来做到这一点?

您可以使用Entity Framework Logging将生成的SQL输出到Visual Studio控制台。就像添加一样简单:

_context.Database.Log = x => Trace.WriteLine(x);

到您的服务或存储库 class(es)。

出于同样的原因,我正在做你正在做的事情。您会看到 LINQ 生成的 SQL 可能是次优的,因此直接复制相同的次优 SQL 供 Dapper 使用在我看来是毫无意义的练习。

我所做的是确定性能最差的 LINQ 查询,并在 SQL 中重写它们 - 从头开始​​ - 以便与 Dapper 一起使用。我最终得到的是整个系统中 LINQ 和 Dapper 的组合,受益于这两种方法的优势,即 LINQ 的快速开发,以及 Dapper 和优化 SQL 查询的性能提升。

我找到了解决我自己问题的良药。我没有拦截查询,而是允许传递谓词并创建与现有函数相同的 Linq 类函数。

public class QueryLinq
{
    private readonly IDatabase _database;

    public QueryLinq(IDatabase database)
    {
        _database = database; // Dapper implementation
    }
   
    public IEnumerable<T> Where<T>(Func<T,bool> predicate)
    {
        var enumerable = _database.Query<T>();
        return enumerable(predicate);
    }
}

// Existing Repository
public class MyRepository
{
    private readonly QueryLinq _queryLinq;

    public MyRepository(QueryLinq queryLinq)
    {
       _queryLinq = queryLinq;
    }
   
    public IEnumerable<MyEntity> SelectMyEntity()
    {
        // Before
        // using (var context = new MyDbContext())
        // {            
        //    context.MyEntity.Where( x => x.Id == 1);
        // }

        // Now
        return _queryLinq.Where<MyEntity>( x => x.Id == 1);
    }
}

在这种方法中,我不需要担心现有查询。

2018 年 8 月 16 日更新:有关此方法的完整详细信息,请访问 here