使用EF查询的最佳方式

时间:2013-07-10 15:50:13

标签: 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构建谓词但没有太大成功(遇到参数错误太大,不得不进行多次查询需要花费时间)。

到目前为止,我发现最成功的方法是实现LEFT OUTER连接并将传入列表连接到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秒才能执行,这对我来说似乎不对。

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

1 个答案:

答案 0 :(得分:1)

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

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

此外,如果您可以控制客户端的行为,您可能希望强制它们每次请求只发送25到100条记录。这样就可以让你以更易于管理的方式处理它们。客户端可能必须向服务器发送100个或更多请求(您可以执行异步,以便它们一次发送〜5个,具体取决于预期的负载配置文件),但至少它不会在5+以上等待从服务器获得针对单个请求的响应的分钟。

顺便说一下,你所说的GroupJoin电话花了15秒,可能是在加入之前必须下载所有700K记录。你看,无法在同一台机器上不存在的对象上进行连接,它必须将所有IncomingInfo个对象(或至少名称+ Date.ToString()连接)发送到数据库,或者它必须在任何连接完成之前请求数据库中的所有记录。您可能必须查看发送到数据库的SQL,以便告知正在使用的方法。但是你可能会发现,在这种情况下,一次查询一个匹配数据库的速度可能会快于连接。

希望有所帮助! ;)