带有EFCore =否/作为异步列表实例化上下文实体的CrossDB查询=有效-我应该采用的真正方法是什么?

问题描述

我有一个正在使用两个数据库服务器的系统:

其中之一是数据库优先-由旧版企业应用程序管理的数据库,我对更改数据库结构没有完全控制权。

第二个是代码优先的代码,我可以完全控制代码优先的数据库进行更改。

安全策略使我无法在代码优先的DB中创建将两个数据库服务器中的表联接起来的视图,这可能是一种根据我在SO帖子中看到的方法进行改进的方法

每个数据库都有一个上下文,因为它们是分开的。

代码优先表中的数据和结构被设计为能够连接到非代码优先数据库,就像它们都在一个数据库中一样。

可以使用这组查询获取所需的工作:

        // Set up EF tables
        var person = await _context1.Person.ToListAsync();
        var labor = await _context1.Labor.ToListAsync();
        var laborCraftRate = await context1.LaborCraftRate.ToListAsync();
        var webUsers = await context2.WebUsers.ToListAsync();
        var workOrders = await _context1.Workorder
           .Where(r => r.Status == "LAPPR" || r.Status == "APPR" || r.Status == "REC")
           .ToListAsync();
        var specialRequests = await _context1.SwSpecialRequest
           .Where(r => r.Requestdate > DateTime.Now)
           .ToListAsync();

        var distributionListQuery = (
                 from l in labor
                 from p in person.Where(p => p.Personid == l.Laborcode).DefaultIfEmpty()
                 from wu in webUsers.Where(wu => wu.Laborcode == l.Laborcode).DefaultIfEmpty()
                 from lcr in laborCraftRate.Where(lcr => lcr.Laborcode == l.Laborcode).DefaultIfEmpty()
                 select new
                 {
                     Laborcode = l.Laborcode,displayname = p.displayname,Craft = lcr.Craft,Crew = l.Crewid,Active = wu.Active,Admin = wu.FrIsAdmin,FrdistLocation = wu.FrdistLocation,}).Where(r => r.Active == "Y" && (r.FrdistLocation == "IPC" || r.FrdistLocation == "IPC2" || r.FrdistLocation == "both"))
                    .OrderBy(r => r.Craft)
                    .ThenBy(r => r.displayname);

        // Build a subquery for the next query to use
        var ptoSubQuery =
           from webUser in webUsers
           join workOrder in workOrders on webUser.Laborcode equals workOrder.Wolablnk
           join specialRequest in specialRequests on workOrder.Wonum equals specialRequest.Wonum
           select new
           {
               workOrder.Wonum,Laborcode = workOrder.Wolablnk,specialRequest.Requestdate
           };

        // Build the PTO query to join with the distribution list
        var ptoQuery =
           from a in ptoSubQuery
           group a by a.Wonum into g
           select new
           {
               Wonum = g.Key,StartDate = g.Min(x => x.Requestdate),EndDate = g.Max(x => x.Requestdate),Laborcode = g.Min(x => x.Laborcode)
           };

        // Join the distribution list and the object list to return
        // list items with PTO information
        var joinedQuery = from dl in distributionListQuery
                          join fl in ptoQuery on dl.Laborcode equals fl.Laborcode
                          select new
                          {
                              dl.Laborcode,dl.displayname,dl.Craft,dl.Crew,dl.Active,dl.Admin,dl.FrdistLocation,fl.StartDate,fl.EndDate
                          };

        // There are multiple records that result from the join,// strip out all but the first instance of PTO for all users
        var distributionList = joinedQuery.GroupBy(r => r.Laborcode)
                            .Select(r => r.FirstOrDefault()).OrderByDescending(r => r.Laborcode).ToList();

同样,这可以在合理但显然不是最佳的时间范围内恢复数据,而我可以在需要此时间的UI中通过在需要时预加载数据来进行恢复。不是最好的,但是有效。

如果我在另一个SO帖子中告诉我应该将变量声明更改为不异步,这将变成跨数据库查询,并且netcore拒绝:

        // Set up EF tables
        var person = _context1.Person;
        var labor = _context1.Labor;
        var laborCraftRate = context1.LaborCraftRate;
        var webUsers = context2.WebUsers;
        var workOrders = _context1.Workorder
           .Where(r => r.Status == "LAPPR" || r.Status == "APPR" || r.Status == "REC");
        var specialRequests = _context1.SwSpecialRequest
           .Where(r => r.Requestdate > DateTime.Now);

添加ToListAsync()是使我需要工作的联接功能的原因。

问-任何人都可以详细说明我正在做的事情的弊端和问题吗?

感谢您帮助我理解!

解决方法

不是说ToList()“不起作用”。问题在于它实现了查询(我认为这是正确的词),并向客户端返回了可能大于预期的数据量。任何进一步的LINQ操作都在客户端进行。这会增加数据库和网络上的负载。在您的情况下,起作用是因为您将所有这些数据都带到了客户端。到那时,不再需要跨数据库查询了。

这是从.NET Core 2.x过渡到3.x时经常遇到的问题。如果无法在服务器端执行操作,则.NET Core 2.x会静默插入类似ToList()之类的内容。 (嗯,不是完全默默无闻。我认为它已记录在某处。但是许多开发人员并未意识到这一点。)3.x停止这样做并会给您一个错误。当人们尝试升级到3.x时,他们经常发现很难将查询转换为可以在服务器端运行的内容。人们拒绝使用明确的ToList(),因为它们的性能很高。但是请记住,这就是它一直在做的事情。如果以前没有性能问题,那么现在就没有问题了。而且至少现在您知道它的实际功能,并在需要时可以对其进行修复。