EF:将导航属性包含在 DbSet 中添加实体的结果中



我正在向我的 DataContext 添加一个实体。在此之后,我必须将此实体发送回视图(向最终用户显示结果)。

DbSet 具有返回新实体的 Add 方法。但是我需要包含导航属性的实体。

在当前时刻,我再次调用 DataContext 并传递 newEntity 的 ID 以查找实体。

public async Task<Entity> AddAsync(Entity entity)
{
    var savedEntity = m_DataContext.Entities.Add(entity);
    await m_DataContext.SaveChangesAsync();
    return await m_DataContext.Entities
        .Include(p=>p.SubEntity)
        .FirstAsync(p=>p.Id==savedEntity.Id);
}
是否可以

在添加操作期间包含导航属性?

我的代码有效,但我正在寻找更优雅的方法。

注意

我意识到这不是代码的实际解决方案。然而,这是OP问题的通用解决方案。

另类设计理念

如果用户输入了此实体的信息,并且它只是持久化回数据库,则无需将对象发送回用户。

更好的情况是,如果 UI 收到成功暂留的通知,然后通过另一个请求从导航属性请求新数据。

"成功持久性"可能只是新添加的实体的新 ID。这将使您的AddAsync return entity.Id。在我看来,您当前实施的 AddAsync 方法违反了 SRP。我的例子:

public async Task<Entity> AddAsync(Entity entity)
{
    var savedEntity = m_DataContext.Entities.Add(entity);
    await m_DataContext.SaveChangesAsync();
    return entity.Id;
}

过早优化

@CallumLinington 我想过这个办法。它根据单一责任模式有机地看起来。但是我有可以查看它们的实体列表(主从模式)。此外,首先我只是将视图上创建的实体添加到此列表中(收到成功回调时,添加了该实体)。但它对我来说并不安全。另一方面,我想限制对数据库的调用。这是以这种方式实施的原因

除非有真正的理由表明它不安全,而不仅仅是您的意见,

并且如果有真正的理由您想要限制对数据库的调用而不仅仅是您的意见,否则我不会限制您的设计

在你

完全证明原因之前对自己施加不必要的限制只会在以后产生糟糕的代码,你最终将不得不"破解"东西,因为你的设计是有缺陷的。

过早优化是一种不好的做法 - 经过深思熟虑和合理的优化是一种很好的做法。

例如,仅仅因为您认为静态方法可以节省执行速度而使用静态方法而不是实例方法是不好的。

首先编写最简单的方法,然后查看实际需要优化的地方。 - 这几乎是TDD的方式。

调用 AddAsync 时,参数实体有两种可能性:

  • 实体。子实体 == 空
  • 实体。子实体 != 空

如果实体。子实体等于空,则包含的结果仍然应该返回空子实体。

如果实体。SubEntity 不为 null,那么添加 savedEntity.SubEntity 也不为 null,而在 saveChanges 之后,savedEntity.SubEntity 甚至包含正确的 Id。

因此,如果您只返回 savedEntity,则返回的值将包含完整的子实体。

在解释实体框架代码优先时,您经常会发现博客和帖子的示例,具有一对多关系:一个博客有很多帖子,而一篇文章只属于一个博客。

代码类似于以下内容:

public class Blog
{
    public int Id {get; set;}
    public string Name {get; set;}
    public ICollection<Post> Posts {get; set;}
}
public class Post
{
    public int Id {get; set;}
    public int BlogId {get; set;} // will become foreign key to Blog
    public virtual Blog Blog {get; set;}
    public string Text {get; set;
}
public class BlogContext : DbContext
{
    public BlogContext() : base("DbTestBlogs") {}
    public DbSet<Blog> Blogs {get; set;}
    public DbSet<Post> Posts {get; set;}
}

以下程序添加了一个包含一些帖子的博客。(子实体)。添加帖子后包括:

class Program
{
    static void Main(string[] args)
    {
        Blog blogToAdd = new Blog()
        {
            Name = "My Blog",
            Posts = new Post[]
            {
                new Post()  {Text = "My 1st Post"},
                new Post()  {Text = "My 2nd Post"},
                new Post()  {Text = "My 3rd Post"},
            },
        };
        // note: Post.BlogId and Post.Blog are not filled!
        Blog addedBlog = AddBlog(blogToAdd);
        Debug.Assert(addedBlog.Posts != null);
        Debug.Assert(addedBlog.Posts.Count() == blogToAdd.Posts.Count());
    }
    private static Blog AddBlog(Blog blogToAdd)
    {
        using (var dbContext = new BlogContext())
        {
            Blog addedBlog = dbContext.Blogs.Add(blogToAdd);
            dbContext.SaveChanges();
            return addedBlog;
        }
    }

如果你运行这个程序,你甚至会发现在返回时Post.BlogId和 Post.Blog 被填满了。因此,在添加过程中,您根本不需要任何包含语句

最新更新