EF6最佳实践,用于加载由上下文跟踪的实体的未映射字段

时间:2017-11-17 11:21:08

标签: entity-framework entity-framework-6

考虑博客数据模型:

Blog:
int Id
ICollection<Post> Posts

Post:
int Id
int BlogId
DateTime Date

然后加载具有最新帖子日期的Blogs(LatestPostDate)并绑定到UI,同时按上下文跟踪它们。

有一些解决方案,例如使用DTO,但上下文不会跟踪结果实体 。 此外,我可以将LatestPostDate设置为NotMapped,定义一个表值函数,并在DbSet上应用SqlQuery。虽然NotMapped字段没有以这种方式加载。

最佳做法是什么?

我尽量不向表中添加列,也避免在加载后计算值。

1 个答案:

答案 0 :(得分:0)

最佳做法是处理ViewModel中的显示问题。

但是由于您不想将实体映射到另一个类,让我们首先看看[NotMapped]变体,使用LINQ来计算最新的发布日期而不是纯SQL。

using System.Linq;

public class Blog {
    public int Id { get; set; }
    public virtual ICollection<Post> Posts { get; set; }

    [NotMapped]
    public DateTime? LatestPostDate {
        get {
            return Posts.OrderBy(p => p.Date).LastOrDefault()?.Date;
        }
    }
}

这样,只有在访问属性LatestPostDate时(可能在UI渲染期间)才会计算该值。您可以eager loading Posts减少数据库访问次数,但这会增加您正在使用的数据集的大小。

var blogs = _dbContext.Blogs.Include(b => b.Posts).ToArray();

但是如果你使用ViewModel,你可以一次填充LatestPostDate

public class BlogViewModel {
    public int Id { get; set; }
    public DateTime? LatestPostDate { get; set; }
}

var viewModels = _dbContext.Blogs.Select(b => new BlogViewModel {
    Id = b.Id,
    LatestPostDate = b.Posts.OrderBy(p => p.Date).LastOrDefault()?.Date;
}).ToArray();

关于上下文不跟踪ViewModel的问题:在编辑用例中,使用ViewModel提供的Id再次加载Entity并映射更新的属性。这使您可以完全控制应该可编辑的属性。作为奖励,ViewModel是进行输入验证,格式化等的好地方。