复杂实体框架查询具有多个表和多对多关系

时间:2011-05-16 18:41:49

标签: c# entity-framework-4 linq-to-entities

我有一段时间让实体框架做我想做的事。我正在编写一个feed聚合器,因此我可以将多个rss提要添加到“FeedList”,它将对所有单个播客进行分组并按pubDate进行排序。

类(除FeedListFeed之外的所有类都具有名为Id的标识列):

  1. Feed(Id是标识主键,具有列表项属性)
  2. FeedItem(Id是标识主键,如int FeedId和Feed Feed属性)
  3. FeedList(FeedListName是字符串和列表供稿属性)
  4. FeedListFeed(多对多链接表,FeedListId和FeedId属性)
  5. 这些映射似乎有效:

    modelBuilder.Entity<FeedListFeed>().HasKey(x => x.FeedId).HasKey(x => x.FeedListId);
    modelBuilder.Entity<FeedList>()
    .HasMany(fl => fl.Feeds).WithMany(f => f.FeedLists)
    .Map(t => t.MapLeftKey("FeedListId")
    .MapRightKey("FeedId")
    .ToTable("FeedListFeeds"));
    

    现在我要做的是在给定FeedListName的FeedList中获取Feeds的最新20个FeedListItem条目。我想出了这个,但还有更好的方法吗?查询是否会实际扩展所有项目,还是在SQL方面做得足够聪明?

    var query =
        from fl in ctx.FeedLists.Include("Feeds").Include("FeedItems")
        from f in fl.Feeds
        from fi in f.Items
        where fl.FeedListName == id
        orderby fi.PubDate descending
        select fi;
    List<FeedItem> items = query.Take(20).ToList();
    

    如果我尝试使用Id列手动链接表,我会收到错误Invalid object name 'dbo.FeedListFeeds1'.如果我拿出将表格相互链接的列表,这会有帮助吗?是否有其他映射可以让它工作?

    var query =
        from fl in ctx.FeedLists
        join flf in ctx.FeedListFeeds on fl.Id equals flf.FeedListId
        join fi in ctx.FeedItems on flf.FeedId equals fi.FeedId
        where fl.FeedListName == id
        orderby fi.PubDate descending
        select fi;
    

1 个答案:

答案 0 :(得分:2)

从地图中删除此行...

modelBuilder.Entity<FeedListFeed>()
            .HasKey(x => x.FeedId)
            .HasKey(x => x.FeedListId);

...因为它有两个问题:

1)如果你想要一个复合键,你不能链HasKey,而是通过匿名类型创建键:

modelBuilder.Entity<FeedListFeed>()
            .HasKey(x => new { x.FeedId, x.FeedListId });

2)(更重要)此行允许EF将FeedListFeed视为不在您的模型中的实体。结果是EF为其创建了一个名为FeedListFeeds1的单独表,因为FeedListFeeds在多对多映射(.ToTable("FeedListFeeds"))中保留为表名。对于多对多映射,您不需要为链接表创建类。链接表由EF内部管理。

修改

您当然也可以完全删除FeedListFeed课程。

对于查询,我会尝试:

var query = from fi in ctx.FeedItems
            where fi.Feed.FeedLists.Any(fl => fl.FeedListName == id)
            orderby fi.PubDate descending
            select fi;

我认为您在模型类中拥有所有必需的导航属性,因此应该可以进行此查询。