【问题标题】:Entity Framework Include Single Object from One-To-Many Relationship实体框架包括来自一对多关系的单个对象
【发布时间】:2016-11-04 03:31:25
【问题描述】:

我正在尝试构建一个查询来获取所有 Tour 对象的列表,并预加载每个 Tour 的最新版本(最新版本是最近创建的)。请参阅下面的模型。每个Tour 可以有多个关联的TourVersion 对象

class Tour {
    public Guid TourId { get; set; }
    public virtual TourVersion CurrentTourVersion { get; set; }
    // Other properties etc.
}
class TourVersion {
    public Guid TourId { get; set; }
    public DateTime CreatedOn { get; set; }
    // Other properties etc.
}

我能够完成我想要为每个Tour 运行另一个查询:

var tours = context.Tours.ToList();

foreach (var tour in tours)
{
    tour.CurrentTourVersion = context.TourVersions
        .Where(t => t.TourId == tour.Id)
        // ToUnixTime is a custom extension method that returns a long
        .OrderByDescending(t => t.CreatedOn.ToUnixTime())
        .FirstOrDefault();
}

我希望能够在单个查询中完成此操作。有什么建议吗?

【问题讨论】:

  • 您已经有一个CurrentTourVersion 导航属性。这意味着 EF 将为您加载它(懒惰或急切地)
  • 你可以改变你的班级结构吗?我认为一对多通常首先在 EF 代码中编码不同
  • 我认为不会,因为每个 Tour 都有多个 TourVersions。 EF 怎么知道要加载多个 TourVersions 中的哪一个?
  • 您当前的班级结构表明每个游览都有一个单一的游览版本。
  • 每个巡演都有多个巡演版本,但只有一个当前版本(即最新版本)。这里的挑战是找到最新版本并在单个查询中为每个游览预取它

标签: c# entity-framework-4 one-to-many


【解决方案1】:

实体框架会自动为您加载相关实体,直到上下文处于活动状态。你得到旅游列表

var tours = dbContext.Tours.ToList();

例如,您可以通过调用获得游览版本

tours[i].CurrentTourVersion;

除非 dbContext 在您获得游览版本之前被放置在某个地方,否则您将需要预先加载(请参阅here)。这样您就可以获取并保留相关的对象。

var tours = dbContext.Tours.Include(obj=>obj.CurrentTourVersion).ToList();

【讨论】:

    【解决方案2】:

    最终解决了这个问题:

    var tours = (from tour in context.Tours
                 join v in context.TourVersions on tour.TourId equals v.TourId
                 where v.CreatedOn == context.TourVersions.Select(b => b.CreatedOn).Max()
                    select new
                    {
                        TourId = tour.Id,
                        CurrentTourVersion = v
                    }).ToList().Select(tour => new Tour
                    {
                        TourId = tour.Id,
                        CurrentTourVersion = tour.CurrentTourVersion
                    });
    
    return tours.ToList();
    

    解释为什么会这样:

    • 使用最新版本加入每个巡演
      • 根据最大日期选择版本来查找最新版本
    • 使用 TourId 和 CurrentTourVersion 字段创建一个匿名对象
    • 将其映射到 Tour 对象列表

    EF 有一个限制,强制您将连接的结果放入匿名对象中。见this answer for more info

    【讨论】:

    • 此限制不存在。我相信你可以在第一个selectselect new Tour
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多