c# - 使用 EF 查询的最佳方式

标签 c# linq entity-framework

使用 LINQ,我无法有效地查询我的 DbContext。 该数据库包含 700,000 多个具有日期、名称和其他信息的实体。

在我的代码中,我有一个新的对象列表(可能有 100,000 个元素)进来,我想查询我的数据库并扣除哪些信息是新实体或哪些信息是需要更新的现有实体.

我想以一种非常有效的方式来做到这一点(如果可能的话,使用单个查询)。

这是我的代码:

public class MyDbContext : DbContext
    {
        public DbSet<MyEntity> MyEntities { get; set; }
    }

    public class MyEntity
    {
        [Key]
        public Guid Id { get; set; }
        public DateTime Date { get; set; }
        public string Name { get; set; }
        public double Amount { get; set; }
        public string Description { get; set; }
    }

    public class IncomingInfo
    {
        public DateTime Date { get; set; }
        public string Name { get; set; }
        public double Amount { get; set; }
    }

    public class Modifier
    {
        public void AddOrUpdate(IList<IncomingInfo> info)
        {
            using (var context = new MyDbContext())
            {                 
                //Find the new information 
                //to add as new entities
                IEnumerable<MyEntity> EntitiesToAdd = ??

                //Find the information 
                //to update in existing entities
                IEnumerable<MyEntity> EntitiesToUpdate = ?? 
            }
        }
    }

有人可以帮助我构建查询吗? 非常感谢。

编辑: 抱歉,我忘了解释我如何认为两个实体相等。 如果 Date 和 Name 属性相同,则相等。

我首先尝试使用 LinqKit PredicateBuilder 构建谓词,但没有成功(遇到参数太大的错误,不得不进行多次查询,耗时)。

到目前为止,我发现的最成功的方法是实现左外连接并将传入列表连接到 DbSet 我是这样实现的:

var values = info.GroupJoin(context.MyEntities,
                    inf => inf.Name + inf.Date.ToString(),
                    ent => ent.Name + ent.Date.ToString(),
                    (inf, ents) => new { Info = inf, Entities = ents })
                 .SelectMany(i => i.Entities.DefaultIfEmpty(),
                    (i, ent) => new { i.Info.Name, i.Info.Amount, i.Info.Date, ToBeAdded = ent == null ? true : false });

IEnumerable<MyEntity> EntitiesToAdd = values.Where(i => i.ToBeAdded)
    .Select(i => new MyEntity
    {
        Id = Guid.NewGuid(),
        Amount = i.Amount,
        Date = i.Date,
        Name = i.Name,
        Description = null
    }).ToList();

我的测试在数据库中包含 700,000 个实体。传入信息列表包含 70,000 项;其中 50,000 个是现有实体,20,000 个是新实体。 此查询执行大约需要 15 秒,这对我来说似乎不合适。

希望这足以寻求帮助。有人可以帮我一个吗? 非常感谢。

最佳答案

我阅读了来自@Leniency 的 pastebin 回复,它涵盖了我要说的一些相同内容,比如查询日期范围并在那里进行比较。不过,该方法的问题在于(取决于这些日期的设置方式)它可能会返回数据库中的所有 700K+ 记录,这会给您带来绝对最差的性能。

我的建议是分析网络拓扑,看看调用数据库的开销到底有多大。我假设这是在从客户端接收这些 IncomingInfo 对象的(网络)服务器上运行的。如果此服务器与您的数据库服务器紧密相连(或在同一台机器上),那么您最好不要优化对数据库的调用。

此外,如果您可以控制客户端的行为,您可能希望强制他们在每个请求中仅发送 25 到 100 条记录。这将使您能够以更易于管理的 block 来处理它们。客户端可能必须向服务器发送 100 个或更多请求(您可以执行异步操作,以便一次发送 ~5 个请求,具体取决于预期的负载配置文件),但至少它不会在那里等待 5+等待从服务器返回对单个请求的响应的分钟数。

顺便说一句,您所说的 GroupJoin 调用花费了 15 秒,这可能是因为在加入之前必须下载所有 700K 条记录。你看,不能对同一台机器上不存在的对象进行连接,它要么必须发送所有 IncomingInfo 对象(或者至少发送 Name+Date.ToString() 连接) 到数据库,或者它必须在可以完成任何连接之前从数据库中请求所有记录。您可能必须查看发送到数据库的 SQL 才能判断正在使用哪种方法。但是您可能会发现,在这种情况下,一次查询一个匹配项的数据库可能比连接更快。

希望对您有所帮助! ;)

关于c# - 使用 EF 查询的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17575260/

相关文章:

c# - event 关键字的真正作用是什么?

多列上的 Linq orderby,其中一个可能为空

c# - 如何在 ef6 中构建简单的属性选择器表达式

c# - 每个实体的 EF6 Code First 审计表

c# - Roslyn,如何获得所有类(class)

c# - MVC 部分页面刷新

linq - 将包含 'with' cte的sql语句转换为linq

c# - Resharper 重新设计了一个 for 循环。这个 LINQ 语句在一行中做的事情太多了吗?

entity-framework - 如何在 Entity Framework 4.4 中实现 DBSet.AddOrUpdate?

c# - WPF:如何将线条绑定(bind)到 UI 元素?