Linq to sql 如何加载多对多LINQ查询?

Linq to sql 如何加载多对多LINQ查询?,linq-to-sql,Linq To Sql,我有以下(相当标准的)表结构: Post <-> PostTag <-> Tag 换句话说,第一篇文章有两个标签,第二篇有一个,第三篇没有 我想在一个查询中加载所有帖子及其标签,但无法找到正确的运算符组合。我已经能够加载只有标签的帖子,或者在有多个标签的情况下加载重复的帖子 鉴于上述数据库,我希望在Post对象的集合属性中接收三篇文章及其标记(如果有)。有可能吗 谢谢我在另一篇帖子中回答了这个问题:。在您的情况下,可能是这样的: DataLoadOptions opti

我有以下(相当标准的)表结构:

Post <-> PostTag <-> Tag
换句话说,第一篇文章有两个标签,第二篇有一个,第三篇没有

我想在一个查询中加载所有帖子及其标签,但无法找到正确的运算符组合。我已经能够加载只有标签的帖子,或者在有多个标签的情况下加载重复的帖子

鉴于上述数据库,我希望在Post对象的集合属性中接收三篇文章及其标记(如果有)。有可能吗


谢谢

我在另一篇帖子中回答了这个问题:。在您的情况下,可能是这样的:

DataLoadOptions options = new DataLoadOptions();    
options.LoadWith<Post>(p => p.PostTag);
options.LoadWith<PostTag>(pt => pt.Tag); 
DataLoadOptions=newdataloadoptions();
options.LoadWith(p=>p.PostTag);
options.LoadWith(pt=>pt.Tag);

尽管要小心-必须在将任何查询发送到数据库之前设置DataLoadOptions-否则,将引发异常(不知道为什么在Linq2Sql中会出现这种情况-可能会在以后的版本中得到修复)。

很抱歉,不,每个post的每个标记都将执行一个额外的查询

使用此代码进行测试:

var options = new DataLoadOptions();
options.LoadWith<Post>(p => p.PostTags);
options.LoadWith<PostTag>(pt => pt.Tag);
using (var db = new BlogDataContext())
{
    db.LoadOptions = options;
    return (from p in db.Posts
            where p.Status != PostStatus.Closed
            orderby p.PublishDateGmt descending
            select p);
}
var options=new DataLoadOptions();
options.LoadWith(p=>p.PostTags);
options.LoadWith(pt=>pt.Tag);
使用(var db=new BlogDataContext())
{
db.LoadOptions=选项;
返回(从数据库中的p返回)
其中p.Status!=PostStatus.Closed
orderby p.PublishDateGmt降序
选择p);
}
在示例数据库中,它将执行4个在生产中不可接受的查询。有人能提出另一个解决方案吗


谢谢,这有点奇怪,因为

DataLoadOptions o = new DataLoadOptions ( );
o.LoadWith<Listing> ( l => l.ListingStaffs );
o.LoadWith<ListingStaff> ( ls => ls.MerchantStaff );
ctx.LoadOptions = o;

IQueryable<Listing> listings = (from a in ctx.Listings
            where a.IsActive == false 
                            select a);
List<Listing> list = listings.ToList ( );
(我缩短了名称,并在选择栏上添加了*)


所以它似乎做了选择ok。

对不起。您给出的解决方案是有效的,但我发现在使用Take(N)分页时它会中断。我使用的完整方法如下:

public IList<Post> GetPosts(int page, int records)
{
    var options = new DataLoadOptions();
    options.LoadWith<Post>(p => p.PostTags);
    options.LoadWith<PostTag>(pt => pt.Tag);
    using (var db = new BlogDataContext())
    {
        db.LoadOptions = options;
        return (from p in db.Posts
                where p.Status != PostStatus.Closed
                orderby p.PublishDateGmt descending
                select p)
                .Skip(page * records)
                //.Take(records)
                .ToList();
    }
}
SELECT p.PostID, p.Title, pt.PostID, pt.TagID, t.TagID, t.Name FROM Posts p
JOIN PostsTags pt ON p.PostID = pt.PostID
JOIN Tags t ON pt.TagID = t.TagID
WHERE p.PostID IN (SELECT TOP 10 PostID FROM Posts)
public IList GetPosts(int页,int记录)
{
var options=new DataLoadOptions();
options.LoadWith(p=>p.PostTags);
options.LoadWith(pt=>pt.Tag);
使用(var db=new BlogDataContext())
{
db.LoadOptions=选项;
返回(从数据库中的p返回)
其中p.Status!=PostStatus.Closed
orderby p.PublishDateGmt降序
选择p)
.跳过(第*页记录)
//.Take(记录)
.ToList();
}
}
使用Take()方法,它会生成一个与您发布的内容类似的查询,但如果我再次添加Take(),它会生成1+nxm查询

因此,我想我现在的问题是:是否有替代Take()方法的方法来分页记录?

谢谢

耶!成功了

如果有人有同样的问题,我会这样做:

public IList<Post> GetPosts(int page, int record)
{
    var options = new DataLoadOptions();
    options.LoadWith<Post>(p => p.PostTags);
    options.LoadWith<PostTag>(pt => pt.Tag);
    using (var db = new DatabaseDataContext(m_connectionString))
    {
        var publishDateGmt = (from p in db.Posts
                              where p.Status != PostStatus.Hidden
                              orderby p.PublishDateGmt descending
                              select p.PublishDateGmt)
                              .Skip(page * record)
                              .Take(record)
                              .ToList()
                              .Last();
        db.LoadOptions = options;
        return (from p in db.Posts
                where p.Status != PostStatus.Closed 
                    && p.PublishDateGmt >= publishDateGmt
                orderby p.PublishDateGmt descending
                select p)
                .Skip(page * record)
                .ToList();
    }
}
public IList GetPosts(int页,int记录)
{
var options=new DataLoadOptions();
options.LoadWith(p=>p.PostTags);
options.LoadWith(pt=>pt.Tag);
使用(var db=newdatabasedatacontext(m_connectionString))
{
var publishDateGmt=(从数据库中的p开始)
其中p.Status!=PostStatus.Hidden
orderby p.PublishDateGmt降序
选择p.PublishDateGmt)
.跳过(第*页记录)
.记录
托利斯先生()
.Last();
db.LoadOptions=选项;
返回(从数据库中的p返回)
其中p.Status!=PostStatus.Closed
&&p.PublishDateGmt>=PublishDateGmt
orderby p.PublishDateGmt降序
选择p)
.跳过(第*页记录)
.ToList();
}
}
这只执行两个查询并加载每个帖子的所有标记

我们的想法是在我们需要的最后一篇文章中获取一些值来限制查询(在本例中,PublishDateGmt列就足够了),然后使用该值而不是Take()来限制第二个查询


感谢您的帮助sirrocco。

我知道这是一篇老文章,但我发现了一种方法,可以在只执行一个查询时使用Take()。诀窍是在嵌套查询中执行Take()

var q = from p in db.Posts
        where db.Posts.Take(10).Contains(p)
        select p;
在上面的查询中使用DataLoadOptions将在一个查询中为您提供前十篇文章,包括它们的关联标记。由此产生的SQL将是以下内容的一个不那么简洁的版本:

public IList<Post> GetPosts(int page, int records)
{
    var options = new DataLoadOptions();
    options.LoadWith<Post>(p => p.PostTags);
    options.LoadWith<PostTag>(pt => pt.Tag);
    using (var db = new BlogDataContext())
    {
        db.LoadOptions = options;
        return (from p in db.Posts
                where p.Status != PostStatus.Closed
                orderby p.PublishDateGmt descending
                select p)
                .Skip(page * records)
                //.Take(records)
                .ToList();
    }
}
SELECT p.PostID, p.Title, pt.PostID, pt.TagID, t.TagID, t.Name FROM Posts p
JOIN PostsTags pt ON p.PostID = pt.PostID
JOIN Tags t ON pt.TagID = t.TagID
WHERE p.PostID IN (SELECT TOP 10 PostID FROM Posts)