最初,我是使用LINQ-to-SQL编写此查询的
var result = from w in PatternDataContext.Windows
join cf in PatternDataContext.ControlFocus on w.WindowId equals cf.WindowId
join p in PatternDataContext.Patterns on cf.CFId equals p.CFId
join r in ResultDataContext.Results on p.PatternId equals r.PatternId
join fi in ResultDataContext.IclFileInfos on r.IclFileId equals fi.IclFileId
join sp in sessionProfileDataContext.ServerProfiles on fi.ServerProfileId equals sp.ProfileId
join u in infrastructure.Users on sp.UserId equals u.Id
where w.Process.Equals(processName)
select u.DistributedAppId;
当我执行它并在QuickWatch中看到
result
时,它显示以下消息:在谷歌搜索时,我在Stackoverflow本身上找到了this topic,在那里我学习了模拟跨上下文连接的方法,并且如此处所建议的,我对查询进行了一些更改:
var result = from w in PatternDataContext.Windows
join cf in PatternDataContext.ControlFocus on w.WindowId equals cf.WindowId
join p in PatternDataContext.Patterns on cf.CFId equals p.CFId
join r in SimulateJoinResults() on p.PatternId equals r.PatternId
join fi in SimulateJoinIclFileInfos() on r.IclFileId equals fi.IclFileId
join sp in SimulateJoinServerProfiles() on fi.ServerProfileId equals sp.ProfileId
join u in SimulateJoinUsers() on sp.UserId equals u.Id
where w.Process.Equals(processName)
select u.DistributedAppId;
该查询使用以下SimulateXyz方法:
private static IQueryable<Result> SimulateJoinResults()
{
return from r in SessionDataProvider.Instance.ResultDataContext.Results select r;
}
private static IQueryable<IclFileInfo> SimulateJoinIclFileInfos()
{
return from f in SessionDataProvider.Instance.ResultDataContext.IclFileInfos select f;
}
private static IQueryable<ServerProfile> SimulateJoinServerProfiles()
{
return from sp in sessionProfileDataContext.ServerProfiles select sp;
}
private static IQueryable<User> SimulateJoinUsers()
{
return from u in infrastructureDataContext.Users select u;
}
但是,即使这种方法也不能解决问题。我仍然在QuickWatch中收到此消息...:
这个问题有什么解决办法吗?除了解决方案,我还想知道为什么问题仍然存在,以及新解决方案如何将其彻底消除,以便下次可以自己解决此类问题。顺便说一下,我是LINQ的新手。
最佳答案
我以前必须这样做,并且有两种方法可以做到。
首先是将所有服务器移到单个上下文中。通过将LINQ-to-SQL指向单个服务器来执行此操作,然后在该服务器中为所有其他服务器创建linked servers。然后,您只需为其他服务器上感兴趣的任何表创建 View ,然后将这些 View 添加到您的上下文中。
第二个方法是通过从一个上下文中提取数据,并仅使用需要连接到另一个上下文中的属性来手动进行连接。例如,
int[] patternIds = SessionDataProvider.Instance.ResultDataContext.Results.Select(o => o.patternId).ToArray();
var results = from p in PatternDataContext.Patterns
where patternIds.Contains(p.PatternId)
select p;
尽管第一个更易于使用,但确实存在很多问题。问题是您依赖SQL Server在链接服务器上表现出色,这是众所周知的缺点。例如,考虑以下查询:
var results = from p in DataContext.Patterns
join r in DataContext.LinkedServerResults on p.PatternId equals r.PatternId
where r.userId = 10;
枚举此查询时,将发生以下情况(我们分别将普通服务器和链接服务器称为
MyServer
和MyLinkedServer
)MyServer
向MyLinkedServer
询问结果MyLinkedServer
将结果发送回MyServer
MyServer
接收这些结果,将它们加入Patterns表中,并仅返回具有Results.userId = 10 所以现在的问题是:何时过滤-在
MyServer
或MyLinkedServer
上?以我的经验,对于这样一个简单的查询,通常会在MyLinkedServer
上完成。但是,一旦查询变得更加复杂,您会突然发现MyServer
正在从MyLinkedServer
请求整个结果表,并在联接后进行过滤!这会浪费带宽,并且如果“结果”表足够大,则可能会将50ms的查询变成50秒的查询!您可以使用存储过程来修复性能不佳的跨服务器联接,但是如果您执行许多复杂的跨服务器联接,则最终可能会为大多数查询编写存储过程,这是很多工作,并且无法达到目的。首先使用L2SQL的过程(不必编写大量SQL)。
相比之下,以下代码将始终在包含“结果”表的服务器上执行过滤:
int[] patternIds = (from r in SessionDataProvider.Instance.ResultDataContext.Results
where r.userId = 10
select r.PatternId).ToArray();
var results = from p in PatternDataContext.Patterns
where patternIds.Contains(p.PatternId)
select p;
哪种情况最适合您,取决于您的最佳判断。
请注意,还有第三种可能的解决方案,我没有提到,因为它并不是真正的程序员解决方案:您可以要求服务器管理员设置replication task,以便每天/每周一次将必要的数据从
MyLinkedServer
复制到MyServer
/月。这仅在以下情况下才是选择:MyLinkedServer
的旧数据MyLinkedServer
MyLinkedServers
表不是很大的关于c# - 在LINQ-to-SQL中使用跨上下文联接,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5429469/