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

时间:2016-03-14 08:23:51

标签: c# asp.net-mvc entity-framework

我正在向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);
}

在添加操作期间是否可以包含导航属性?

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

2 个答案:

答案 0 :(得分:-1)

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

  • entity.SubEntity == null
  • entity.SubEntity!= null

如果entity.SubEntity等于null,那么include的结果仍然应该返回一个null SubEntity。

如果entity.SubEntity不为null,则在添加savedEntity.SubEntity之后也不为null,并且在saveChanges之后,savedEntity.SubEntity甚至包含正确的ID。

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

在解释实体框架代码时,您经常会找到博客和帖子的示例,其中包含一对多的关系:一个博客有很多帖子,一个帖子只属于一个博客。

代码类似于以下内容:

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已填满。因此,在添加过程中,您根本不需要任何包含语句

答案 1 :(得分:-1)

N.B

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

另类设计理念

如果用户输入了该实体的信息,并且只是将其持久化回数据库,那么您就不需要将该对象发送回用户。

如果UI被通知成功持久性,然后通过另一个请求从导航属性中请求新数据,那会更好。

&#34;成功的持久性&#34; 可能只是新添加的实体的新ID。这会让您AddAsyncreturn 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我是这么想的。它根据单一责任模式有机地看待。但我有可能查看它们的实体列表(主 - 细节模式)。此外,首先我只是在视图实体上添加了一个创建到此列表中(当收到成功回调时添加了该实体)。但它对我来说并不安全。另一方面,我想限制对数据库的调用。这是以这种方式实施的原因

除非有正确的理由认为它不安全且不仅仅是您的意见,如果有真正的理由您想要限制对数据库的调用而不仅仅是您的意见,我不会&# 39;限制你的设计

在你完全证明原因之前对自己施加不必要的限制只会导致以后出现错误的代码,并且你最终不得不&#34; hack&#34;事情因为你的设计存在缺陷。

过早优化是一种不好的做法 - 经过充分考虑和合理的优化是一种很好的做法。

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

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