如何加载多对多LINQ查询?

如何加载多对多LINQ查询?

How to load Many to many LINQ query?

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

1
Post <-> PostTag <-> Tag

假设我有以下记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
PostID Title
1,     'Foo'
2,     'Bar'
3,     'Baz'

TagID Name
1,    'Foo'
2,    'Bar'

PostID TagID
1      1
1      2
2      2

换句话说,第一个帖子有两个标签,第二个帖子有一个标签,而第三个没有任何标签。

我想在一个查询中加载所有帖子及其标签,但无法找到合适的运算符组合。 我已经可以只加载带有标签的帖子,也可以加载多个标签时的重复帖子。

给定上面的数据库,我想在Post对象的collection属性中接收三个帖子及其标签(如果有)。 有可能吗?

谢谢


好极了!有效。

如果有人遇到相同的问题,这就是我所做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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();
    }
}

这仅执行两个查询并为每个帖子加载所有标签。

想法是获得一些值以将查询限制在我们需要的最后一个帖子(在这种情况下,PublishDateGmt列就足够了),然后用该值而不是Take()限制第二个查询。

感谢您的帮助sirrocco。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();
    }
}

注释了Take()方法后,它会生成与您发布的查询类似的查询,但是如果我再次添加Take(),它将生成1 + N x M个查询。

所以,我想我现在的问题是:Take()方法是否有替代方法可对记录进行分页?

谢谢


有点奇怪,因为

1
2
3
4
5
6
7
8
9
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 ( );

结果如下:

1
2
3
4
5
6
7
8
9
10
11
SELECT [t0].*, [t1].*, [t2].*, (
SELECT COUNT(*)
FROM [dbo].[LStaff] AS [t3]
INNER JOIN [dbo].[MStaff] AS [t4] ON [t4].[MStaffId] = [t3].[MStaffId]
WHERE [t3].[ListingId] = [t0].[ListingId]
) AS [value]
FROM [dbo].[Listing] AS [t0]
LEFT OUTER JOIN ([dbo].[LStaff] AS [t1]
INNER JOIN [dbo].[MStaff] AS [t2] ON [t2].[MStaffId] = [t1].[MStaffId]) ON
[t1].[LId] = [t0].[LId] WHERE NOT ([t0].[IsActive] = 1)
ORDER BY [t0].[LId], [t1].[LStaffId], [t2].[MStaffId]

(我缩短了名称,并在选择项上添加了*)。

这样看来就可以了。


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

1
2
3
var q = from p in db.Posts
        where db.Posts.Take(10).Contains(p)
        select p;

在上面的查询中使用DataLoadOptions将在一个查询中为您提供前十个帖子,包括它们的关联标签。生成的SQL将是以下内容的简洁得多:

1
2
3
4
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)

很抱歉,不行,Eager Loading将为每个帖子的每个标签执行一个额外的查询。

经过以下代码测试:

1
2
3
4
5
6
7
8
9
10
11
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);
}

在示例数据库中,它将执行4个在生产中不可接受的查询。谁能建议其他解决方案?

谢谢


我已经在另一篇文章中回答了这个问题:关于渴望加载。在您的情况下,可能类似于:

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

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


推荐阅读

    linux设备加载命令行?

    linux设备加载命令行?,设备,系统,信息,数字,首页,软件,密码,终端,文件,键盘,L

    linux命令行加载中文?

    linux命令行加载中文?,名称,系统,不了,传播,网上,状态,管理,中文,终端,命令,L

    linux查询url命令?

    linux查询url命令?,系统,网址,工具,数据,网站,命令,传播,软件,地址,标准,linu

    linux启动加载命令行?

    linux启动加载命令行?,服务,系统,数字,首页,终端,环境,命令,方法,脚本,文件,

    linux查询命令进程?

    linux查询命令进程?,系统,名称,总量,情况,状态,进程,材料,工具,电脑,数据,怎

    linux命令导出表结构?

    linux命令导出表结构?,工作,系统,信息,地址,网络,命令,目录,云南,数据,服务,l

    查询linux内存命令?

    查询linux内存命令?,系统,情况,信息,工具,电脑,状态,命令,内存,发行,总量,查

    linux命令查询屏保?

    linux命令查询屏保?,系统,工作,工具,信息,地址,图片,命令,目录,基础,电脑,lin

    linux加载库的命令?

    linux加载库的命令?,系统,地址,信息,设备,标准,服务,命令,名字,工具,首页,lin

    linux链路查询命令?

    linux链路查询命令?,系统,信息,工作,地址,命令,工具,时间,盘中,基础,名字,lin

    linux查询文件夹命令?

    linux查询文件夹命令?,系统,软件,电脑,命令,文件,文件夹,单位,第三,档案,数

    linux加载驱动命令6?

    linux加载驱动命令6?,信息,名称,设备,系统,电脑,软件,材料,下来,命令,权限,li

    linux加载过滤命令?

    linux加载过滤命令?,数据,系统,工具,标准,官网,灵活,最新,命令,文件,文件名,l

    linux查询线程命令?

    linux查询线程命令?,系统,第一,线程,命令,进程,代码,分时,软件,选项,界面,如

    linux查询内核数命令?

    linux查询内核数命令?,系统,第一,信息,命令,实时,软件,电脑,内核,个数,界面,

    linux查询ip命令?

    linux查询ip命令?,地址,网络,信息,设备,系统,电脑,终端,命令,中心,技术指标,l

    linux查询所有命令?

    linux查询所有命令?,工作,地址,系统,命令,信息,目录,工具,基础,文件,内容,lin

    linux日志命令查询?

    linux日志命令查询?,系统,名称,信息,实时,电脑,对比,最新,日志,命令,环境,Lin

    linux文本查询命令?

    linux文本查询命令?,标准,命令,文件,工具,数据,信息,位置,系统,内容,文本,Lin

    命令查询linux包安装?

    命令查询linux包安装?,软件,地方,地址,名字,系统,名称,信息,路径,命令,文件,