简体   繁体   English

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

[英]EF: Include navigation property to result of adding entity in DbSet

I am adding an entity to my DataContext. 我正在向DataContext添加一个实体。 After this, I have to send this entity back on view (show result to end user). 在此之后,我必须在视图上发送此实体(向最终用户显示结果)。

DbSet has Add method that returns back new entity. DbSet具有返回新实体的Add方法。 But I need my entity with included navigation properties. 但我需要包含导航属性的实体。

In the current moment, I make one more call to DataContext and passing newEntity's Id to find the entity. 在当前时刻,我再调用一次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);
}

Is it possible to include navigation property during adding operation? 是否可以在添加操作期间包含导航属性?

My code works but I am looking for way to do it more gracefully. 我的代码有效,但我正在寻找更优雅的方式。

When your AddAsync is called there are two possibilities for parameter entity: 调用AddAsync时,参数实体有两种可能性:

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

If entity.SubEntity equals null, then the result of an include still ought to return a null SubEntity. 如果entity.SubEntity等于null,那么include的结果仍然应该返回null SubEntity。

If entity.SubEntity is not null, then after adding savedEntity.SubEntity is also not null, and after saveChanges, savedEntity.SubEntity even contains the correct Ids. 如果entity.SubEntity不为null,则在添加savedEntity.SubEntity之后也不为null,并且在saveChanges之后,savedEntity.SubEntity甚至包含正确的ID。

So if you just return savedEntity, the returned value will include the complete subEntity. 因此,如果您只返回savedEntity,则返回的值将包含完整的subEntity。

When explaining Entity-Framework code-first you quite often find the example of Blogs and Posts, with a one-to-many relation: one blog has many posts, and one post belongs to exactly one blog. 在解释实体框架代码时,您经常会找到具有一对多关系的博客和帖子示例:一个博客有很多帖子,一个帖子只属于一个博客。

The code is similar to the following: 代码类似于以下内容:

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;}
}

The following program adds a Blog with some Posts. 以下程序添加了一些博客和一些帖子。 ( subentities ). 子实体 )。 After adding the posts are included: 添加帖子后包括:

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;
        }
    }

If you run this program you'll even find that upon return the Post.BlogId and Post.Blog are filled. 如果你运行这个程序,你甚至会发现在返回时Post.BlogId和Post.Blog被填充。 So during adding you don't need any include statement at all 所以在添加过程中根本不需要任何include语句

NB NB

I realise this isn't an actual solution to the code. 我意识到这不是代码的实际解决方案。 However it is a general solution to the OP's question. 然而,它是OP问题的一般解决方案。

Alternative Design Idea 另类设计理念

If the user has entered the information for this entity, and it is just getting persisted back to the database then you don't need to send the object back to the user. 如果用户输入了该实体的信息,并且它刚刚被持久化回数据库,那么您不需要将该对象发送回用户。

What would be better is if the UI was notified of successful persistence and then requested the new data from the navigation property via another request. 如果UI被通知成功持久性,然后通过另一个请求从导航属性请求新数据,那会更好。

The "successful persistence" could just be the new ID of the newly added entity. “成功的持久性”可能只是新添加的实体的新ID。 This would make your AddAsync do return entity.Id . 这将使您的AddAsync确实return entity.Id In my opinion you're violating SRP with the current implementation of the AddAsync method. 在我看来,你使用AddAsync方法的当前实现违反了SRP。 My example: 我的例子:

public async Task<Entity> AddAsync(Entity entity)
{
    var savedEntity = m_DataContext.Entities.Add(entity);

    await m_DataContext.SaveChangesAsync();

    return entity.Id;
}

Premature Optimisations 过早的优化

@CallumLinington I thought about this way. @CallumLinington我是这么想的。 And it looks organically according to single responsibility pattern. 它根据单一责任模式有机地看待。 But I have the list of entities with possibility to view them (master-detail pattern). 但我有可能查看它们的实体列表(主 - 细节模式)。 Moreover, in first I just added a created on the view entity to this list (when received the successful call back that entity was added). 此外,首先我只是在视图实体上添加了一个创建到此列表中(当收到成功回调时添加了该实体)。 But it didn't look safely for me. 但它对我来说并不安全。 From another hand, I want to limit calls to the database. 另一方面,我想限制对数据库的调用。 It is the reason for implementation in this way 这是以这种方式实施的原因

Unless there is a genuine reason that it isn't safe and not just your opinion and again if there is a genuine reason you want to limit calls to the database and not just your opinion, I wouldn't limit your design . 除非有一个真正的原因,它不安全,不仅仅是你的意见,如果有一个真正的理由你想要限制对数据库的调用,而不仅仅是你的意见, 我不会限制你的设计

Putting unnecessary limitations on yourself before you have even fully justified the reasons will just make for bad code later on, and you will end up having to "hack" things in because your design is flawed. 在你完全证明原因之前对自己施加不必要的限制只会导致以后的错误代码,并且你最终因为你的设计存在缺陷而“破解”内容。

Premature optimisation is a bad practise - well considered and justified optimisations are a good practise. 过早优化是一种不好的做法 - 经过充分考虑和合理的优化是一种很好的做法。

So for example, using a static method instead of a instance method just because you think it will save execution speed is bad. 因此,例如,仅仅因为您认为它将节省执行速度而使用静态方法而不是实例方法是不好的。

Write the simplest way first then see where the optimisations are actually needed. 先写出最简单的方法然后看看实际需要优化的地方。 - this is nearly the TDD way. - 这几乎是TDD方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM