我有以下的Linq2Sql并且它正在为我的'SELECT'语句进行多次往返。我不知道为什么。首先是代码,然后是解释: -
from p in db.Questions
select new Models.Question
{
Title = p.Title,
TagList = (from t in p.QuestionTags
select t.Tag.Name).ToList()
}
现在数据库是
问题< -one to many-> QuestionTags< -many to one-> Tag
所以一个问题有一对多的标签,中间有一个链接表。这样,我可以多次重复使用标签。 (如果有的话,我会对更好的架构持开放态度。)
执行此操作会执行Linq2Sql生成的以下Sql代码
SELECT [t0].[QuestionId] AS [ID], etc.... <-- that's the good one
exec sp_executesql N'SELECT [t1].[Name]
FROM [dbo].[QuestionTags] AS [t0]
INNER JOIN [dbo].[Tags] AS [t1] ON [t1].[TagId] = [t0].[TagId]
WHERE [t0].[QuestionId] = @x1',N'@x1 int',@x1=1
第二个sql块被列为2x ..我认为这是因为第一个sql块返回了两个结果,所以第二个sql块会从第一个结果中触发每个结果。
有什么方法可以使这个sql语句而不是1 + n,其中n =第一个查询的结果数?
我尝试了Eager和Lazy加载,没有区别。
DataLoadOptions dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Question>(x => x.QuestionTags);
dataLoadOptions.LoadWith<QuestionTag>(x => x.Tag);
db.LoadOptions = dataLoadOptions;
答案 0 :(得分:5)
ToList()肯定会阻止你。您应该对整个查询执行ToList()。
我认为你可以做的另一件事是使用“let”。我认为在这种情况下,它可以创建延迟执行并包含在表达式树中,但是YMMV。
from p in db.Questions
let Tags = (from t in p.QuestionTags
select t.Tag.Name)
select new Models.Question
{
Title = p.Title,
TagList = Tags
}
答案 1 :(得分:2)
这可能是LINQ本身不够的情况之一。您是否考虑过将此逻辑编写为UDF或SPROC,并简单地使用LINQ来调用它? LINQ-to-SQL非常擅长调用(实体框架在UDF中不是很好)。
然后你可以在数据库中进行标记组合,并将其作为varchar返回,例如。没有游标就有一个TSQL技巧:
DECLARE @foo varchar(max)
SET @foo = ''
SELECT @foo = @foo + [SomeColumn] + ',' -- CSV
FROM [SomeTable]
WHERE -- some condition
(也许删除尾随的逗号)
运行此操作后,@foo
将成为值的CSV - 如果您返回单行,则非常有效。如果你要返回多个主要行,那就不那么好了。
答案 2 :(得分:2)
您可以尝试在此对象关联上配置Eager Loading。类似的东西:
var dlo = new DataLoadOptions();
// Configure eager loading
dlo.LoadWith<Question>(q => q.QuestionTags);
_context = new WhateverContext();
_context.LoadOptions = dlo;
但您可能需要稍微重构一下代码。基本上你告诉框架发出SQL来引入更广泛的对象图,而不是等到访问对象关联(延迟加载是默认的)。
也许看(http://blog.codeville.net/2007/12/02/linq-to-sql-lazy-and-eager-loading-hiccups/)。顺便说一句不同的史蒂文!
答案 3 :(得分:0)
我想问题是你应该为整个查询调用.ToList()。这将从db。中返回整个集合。
在您的情况下,第一个SQL命令仅返回所有问题的ID,然后,每个问题都会发生单个SQL调用(在foreach循环中迭代期间) - 请参阅@ x1 param。
答案 4 :(得分:0)
你可以像这样进行延迟加载:
from p in db.Questions
let Tags = GetTags(Questions.Id)
select new Models.Question
{
Title = p.Title,
TagList = LazyList<string>(Tags)
}
public IQueryable<string> GetTags(int questionId) {
from qt in db.QuestionTags
join t in db.Tags on qt.TagId equals t.Id
where qt.questionId = questionId
select t.Name
}
LazyList是一个实现IList的IQueryable容器。一旦枚举了TagList属性,就会执行存储在里面的IQueryable。
LazyList类由Rob Connery编写,可在此处找到:http://blog.wekeroad.com/blog/lazy-loading-with-the-lazylist/