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

C# EF:将导航属性包含到在DbSet中添加实体的结果中,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,我正在向我的DataContext添加一个实体。在此之后,我必须将该实体发送回视图(将结果显示给最终用户) DbSet具有返回新实体的方法。但我需要包含导航属性的实体 在当前时刻,我再次调用DataContext并传递newEntity的Id以查找实体 public async Task<Entity> AddAsync(Entity entity) { var savedEntity = m_DataContext.Entities.Add(entity); awa

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

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

在当前时刻,我再次调用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);
}
公共异步任务AddAsync(实体) { var savedEntity=m_DataContext.Entities.Add(entity); 等待m_DataContext.saveChangesSync(); return wait m_DataContext.Entities .Include(p=>p.SubEntity) .FirstAsync(p=>p.Id==savedEntity.Id); } 是否可以在添加操作期间包含导航属性


我的代码可以工作,但我正在寻找更优雅的方法。

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

  • entity.SubEntity==null
  • 实体。子实体!=空的
如果entity.SubEntity等于null,则include的结果仍应返回null子实体

如果entity.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;}
}
如果你运行这个程序,你甚至会发现返回后Post.BlogId和Post.Blog都被填满了。因此,在添加过程中,您根本不需要任何include语句 我意识到这不是代码的实际解决方案。然而,这是OP问题的一般解决方案

另类设计理念
如果用户已经输入了该实体的信息,并且该实体刚刚被持久化回数据库,那么您不需要将对象发送回用户

如果用户界面收到成功持久化的通知,然后通过另一个请求从导航属性请求新数据,则更好

“成功持久化”可能只是新添加实体的新ID。这将使您的
AddAsync
do
返回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;
}
公共异步任务AddAsync(实体) { var savedEntity=m_DataContext.Entities.Add(entity); 等待m_DataContext.saveChangesSync(); 返回实体Id; } 过早优化
@卡拉姆林顿,我是这样想的。按照单一责任模式,它看起来是有机的。但是我有可以查看的实体列表(主细节模式)。此外,在第一次中,我只是将在视图实体上创建的实体添加到此列表中(当收到成功的回调时,该实体被添加)。但它对我来说并不安全。另一方面,我想限制对数据库的调用。这是以这种方式实施的原因


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

在充分证明理由之前对自己施加不必要的限制只会在以后产生糟糕的代码,而你最终将不得不“破解”一些东西,因为你的设计有缺陷

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

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


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

不知道是否可能,但您仍然可以使用存储过程对数据库进行一次调用。如果用户已输入此实体的信息,它只是被持久化回数据库,然后您就不需要将对象发送回用户。更好的是,如果用户界面收到成功持久化的通知,然后从导航属性请求新数据,“成功持久化”可能只是新添加实体的新ID。这将使您的
AddAsync
do
返回entity.Id
。目前我认为你用这种方法违反了SRP。@Callumlington我是这样想的。按照单一责任模式,它看起来是有机的。但是我有可以查看的实体列表(主细节模式)。此外,在第一次中,我只是将在视图实体上创建的实体添加到此列表中(当收到成功的回调时,该实体被添加)。但它对我来说并不安全。另一方面,我想限制对数据库的调用。这是以这种方式实现的原因。除非有真正的原因,否则它是不安全的,而不仅仅是你的意见。同样,如果有真正的原因,你想限制对数据库的调用,而不仅仅是你的意见,我不会限制你的设计。在你还没有充分证明理由之前就对自己进行不必要的限制,这只会在以后你不得不“破解”一些东西的时候造成糟糕的代码,因为你的设计有缺陷。它不起作用。当我试图在视图中获取子实体的某些属性时,我明白我的代码有问题。
public async Task<Entity> AddAsync(Entity entity)
{
    var savedEntity = m_DataContext.Entities.Add(entity);

    await m_DataContext.SaveChangesAsync();

    return entity.Id;
}