6

我有以下(非常标准的)表结构:

Post <-> PostTag <-> Tag

假设我有以下记录:

PostID Title
1,     'Foo'
2,     'Bar'
3,     'Baz'

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

PostID TagID
1      1
1      2
2      2

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

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

鉴于上面的数据库,我想在 Post objects 的集合属性中接收三个帖子及其标签(如果有)。有可能吗?

谢谢

4

6 回答 6

2

耶!有效。

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

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() 来限制第二个查询。

感谢您的帮助西洛克。

于 2008-09-17T14:24:22.213 回答
1

对不起。您提供的解决方案有效,但我发现它在使用 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();
    }
}

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

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

谢谢

于 2008-09-17T13:46:53.473 回答
1

这有点奇怪,因为

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 ( );

结果如下查询:

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]

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

所以它似乎可以选择。

于 2008-09-17T06:53:28.863 回答
0

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

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

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

于 2008-09-17T04:26:56.440 回答
0

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

使用此代码进行测试:

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 个查询,这在生产中是不可接受的。任何人都可以提出另一种解决方案吗?

谢谢

于 2008-09-17T04:35:02.083 回答
0

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

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

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

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)
于 2010-10-20T17:42:41.083 回答