0

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

其中之一是数据库优先——由遗留企业应用程序管理的数据库,我无法完全控制更改数据库结构。

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

安全策略阻止我在代码优先数据库中创建一个连接来自两个数据库服务器的表的视图,根据我在 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() 是允许我需要工作的连接功能的原因。

问 - 谁能详细说明我正在做的事情可能存在的缺点和问题?

谢谢你帮助我理解!

4

1 回答 1

1

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

这是从 .NET Core 2.x 过渡到 3.x 期间经常出现的问题。如果无法在服务器端执行操作,.NET Core 2.x 会静默插入类似ToList(). (嗯,不是完全静默。我认为它被记录在某个地方。但许多开发人员并没有意识到它。) 3.x 停止这样做并且会给你一个错误。当人们尝试升级到 3.x 时,他们经常发现很难将查询转换为可以在服务器端运行的东西。人们拒绝投入明确的ToList()因为太多的表现。但请记住,这就是它一直在做的事情。如果以前没有性能问题,那么现在就没有了。至少现在你知道它实际上在做什么,并且如果你真的需要,可以修复它。

于 2020-11-06T17:08:11.837 回答