使用LINQ包含嵌套实体

20

我第一次尝试使用LINQ,并且我正在使用EF 4.1 Code First。

我的实体包含其他实体的嵌套列表,例如:

class Release
{
    int ReleaseID { get; set; }
    string Title { get; set; }
    ICollection<OriginalTrack> OriginalTracks { get; set; }
}

class OriginalTrack
{
    int OriginalTrackID { get; set; }
    string Title { get; set; }
    ICollection<Release> Releases { get; set; }
    ICollection<OriginalArtist> OriginalArtists { get; set; }
}

class OriginalArtist
{
    int OriginalArtistID { get; set; }
    string Name { get; set; }
    ICollection<OriginalTrack> OriginalTracks { get; set; }
}

我想知道如何在一个LINQ查询中以最快的方式获取所有ReleaseID == 某个值的信息。

我已经做过功课,但发现一些解决方案需要隐式重建一个带有所需数据的对象(通常是匿名对象)。我想要从数据库中以与数据库中保存的精确格式相同的格式获取数据,即使用相关ReleaseID检索和填充Lists中的所有OriginalTrack和OriginalArtist数据的Release对象。

我知道Include(),但不确定如何应用于多个实体。

非常感谢任何帮助。

3个回答

14

使用 Include。这就是Include的目的,没有理由编写一堆嵌套的选择语句。

context.Releases.Include("OriginalTracks.OriginalArtist")
    .Where(release => release.ReleaseID == id);

这种方法更易于编写和阅读,并保留了现有的数据结构。

使用Include时,您需要指定要返回的属性的名称 - 这意味着名称应与代码中存在的名称相同,而不是数据库中的名称。例如:

  • .Include("OriginalTracks") 将在每个发布项上包含 OriginalTracks 属性
  • .Include("OriginalTracks.OriginalArtist") 将在每个发布项上包含 OriginalTracks 属性以及每个 Track 上的 OriginalArtist(请注意,在包括 OriginalTrack 的同时包括 OriginalArtist 在语法或逻辑上都是不可能的
  • .Include("OriginalTracks").Include("OtherProperty") 将在每个发布项上包括 OriginalTracks 和 OtherProperty 对象。

您可以链式添加任意多个,例如:

.Include("Tracks.Artist").Include("AnotherProperty")
    .Include("ThirdProperty.SomeItems").Where(r => r.something);

这是完全有效的。唯一的要求是将 Include 放在 EntitySet 上,而不是查询上 - 你不能使用 .Where().Include()


你能给我一个链接包含的链接的例子吗?我看到过指定两个不同路径的情况,但没有多个嵌套对象的情况。上面的例子只会返回原始艺术家,还是会返回该路径上的所有数据? - Will Bithell
@Will 它会将该路径上的所有数据都返回。我会编辑并提供更多信息。 - Kirk Broadhurst
谢谢,看起来不错。我现在在搜索包含的实体中遇到了困难,我猜这是不可能的?比如说 Tracks.Artists.Name == 搜索词? - Will Bithell
@Will 这就是问题所在。称之为“条件包含” - 这就是 msarchet 的链接有用的地方。(http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx) 本质上,您使用匿名类型构建查询,然后从该查询中选择根。请查看该链接或以下链接:https://dev59.com/-XI_5IYBdhLWcg3wEe1u https://dev59.com/M3NA5IYBdhLWcg3wH6AW (在 SO 上搜索 'ef conditional include') - Kirk Broadhurst
@KirkBroadhurst,也许你指的是EF的旧版本,但实际上你可以Where(或任何其他IQueryable方法)之后调用Include,因为Include扩展了IQueryable。请参见https://github.com/mono/entityframework/blob/master/src/EntityFramework/QueryableExtensions.cs#L450 - haim770

10

不必担心在此处使用include

只需像以下示例一样操作即可

var query = 
    from release in ctx.Releases
    select new {
        release,
        originalTracks = from track in release.OriginalTracks
                         select new {
                               track,
                               releases = track.Releases,
                               orignialArtist = from artist in track.OriginalArtists
                                                select new {
                                                     artist,
                                                     artist.OriginalTracks
                                                }
                         }
        }

var Releases = query.Select(x => x.Release);

应该加载所有的数据

我参考了这篇文章中的信息。

http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx


好的,那似乎是我需要的,我想明天试一试,但我会标记为答案。谢谢! - Will Bithell
1
@msarchet,根据您提供的链接,这不是条件包含。那个链接涉及到基于某些条件对子对象进行包含(或过滤);这是一个更有趣的问题。这只是一个简单的选择与包含。 - Kirk Broadhurst

9
要在不使用字符串文字的情况下包含嵌套实体,请使用 Select,例如:
context.Releases.Include(r => r.OriginalTracks.Select(t => t.OriginalArtist))
    .Where(release => release.ReleaseID == id);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接