【问题标题】:C# Complex Linq - Join two table within a subqueryC# Complex Linq - 在子查询中连接两个表
【发布时间】:2015-10-30 19:41:50
【问题描述】:

我目前正在开发一个使用非常复杂的数据库的系统。

我需要从多个表和关联中编译信息以显示这样的列表(我有很多):

[List] (Class `List`)
     [Id]
     [EntityId]
     [Name]
     [Description]
     [Users] (From `List<User> List.AssignedUsers` joined to `List<ListMember> List.Members`)
         [Id]
         [EntityId]
         [Username]
         [FullName]
         [Email]
         [ListId]
         [Order] (From `ListOrder` property in `ListMember` object)
         [Status] (From `Status` property in `ListMember` object)
             [Id]
             [NameEn]
             [NameFr]
             [Color]
             [Type]
             [Tag]
             [Options]

在此,List.AssignedUsers 是可以访问该列表的用户列表。 List.Members 是列表中当前活跃用户的列表,包含他们的状态。如果AssignedUser 不在Members 中,则StatusOrder 属性必须为空。

数据库的设计方式如下:

这是我尝试使用的代码:

var lists =
    await (from l in db.Lists.Include("Members").Include("AssignedUsers")
           where l.DateDeleted == null
           select new ListModel
           {
               Id = l.Id,
               EntityId = l.EntityId,
               Name = l.Name,
               Description = l.Description,
               Users = (
                   from u in l.AssignedUsers
                   join lms in l.Members on u.Id equals lms.UserId into members
                   from lm in members.DefaultIfEmpty()
                   select new UserModel
                   {
                       Id = u.Id,
                       EntityId = u.EntityId,
                       Username = u.Username,
                       FullName = u.FullName,
                       Email = u.Email,
                       ListId = l.Id,
                       Order = (lm == null ? lm.ListOrder : -1),
                       Status = (lm != null ? new StatusModel
                       {
                           Id = lm.Status.Id,
                           Type = lm.Status.Type,
                           Color = lm.Status.Color,
                           Tag = lm.Status.Tag,
                           NameEn = lm.Status.NameEn,
                           NameFr = lm.Status.NameFr,
                           Options = lm.Status.AvailableOptions
                       } : null)
                   }
               ).ToList()
           }).ToListAsync();

return lists;

问题是这个查询非常慢,我的w3wp.exe 进程没有返回结果,而是一个漂亮的窗口告诉我.NET 崩溃了。错误日志只说:

Faulting application name: w3wp.exe, version: 10.0.10240.16384, time stamp: 0x559f3dad
Faulting module name: ntdll.dll, version: 10.0.10240.16430, time stamp: 0x55c599e1
Exception code: 0xc00000fd
Fault offset: 0x0003dcb9
Faulting process id: 0x4998
Faulting application start time: 0x01d1134884f4b8dd
Faulting application path: C:\Windows\SysWOW64\inetsrv\w3wp.exe
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll
Report Id: 52069c20-912c-428a-b4fc-271851dbaba0
Faulting package full name: 
Faulting package-relative application ID: 

现在,我尝试了其他几种方法,但我正在寻找性能最高的方法,如果 LINQ 做不到,我会直接在 SQL 中做!

【问题讨论】:

  • 如果您正在寻找最高效的方式并且对普通 SQL 感到满意,那么 dapper dot net 可能是一个可行的选择。一些基准测试:dontpaniclabs.com/blog/post/2014/05/01/…
  • @silencedmessage 好吧,我对 SQL 很满意,但如果有办法用 EF 做到这一点,我会喜欢这种方式。另外,不需要 Dapper,EF 可以执行普通的 SQL 查询,并根据需要将结果返回到 DTO 对象中。

标签: c# sql-server entity-framework linq exception


【解决方案1】:

这很慢,因为嵌套的 ToList 调用阻止了库使用单个查询。

如果您只是为您的对象、连接和所有内容构建一个很好的描述,并在最后调用ToArray(为什么列出?),那很好,但您的方式调用查询的第一部分一开始,然后为每个返回的项目调用子查询来填充结果。

至于它为什么会崩溃,同样写得很好:lm == null ? lm.ListOrder : -1——你可以通过简单的调试过程很容易地看到它。

【讨论】:

  • ToList() 是因为模型有一个强类型的public ICollection&lt;UserModel&gt; Users { get; set; }。但是 ToList 和 ToArray 有什么区别呢?并感谢平等通知(周末,没看到!)
  • 更正了相等性并使用IEnumerable&lt;UserModel&gt; 而不是ICollection,然后删除了ToList。立即加载,谢谢!
  • 是的,ICollectionIQueryable 完全相反,这是 EF 的基础。一旦您退出 IQueryable 世界,您就不再在服务器上运行,而是在您自己的计算机上运行。
猜你喜欢
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-23
相关资源
最近更新 更多