在实体框架中使用外键更新实体和导航属性之间的区别 [英] Difference between updating an entity by using a foreign key and using the navigation properties In Entity Framework

查看:103
本文介绍了在实体框架中使用外键更新实体和导航属性之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

- 我想知道使用外键更新实体之间的区别,并使用Entity Framework中的导航属性。

-I Want to know the Difference between updating an entity by using foreign key and using the navigation properties in Entity Framework.

- 有一种方法来更新复杂对象只能一次调用数据库?

-Is there a way to update a complex object with only one call to the database?

推荐答案

使用外键更新实体比导航属性更为方便,因为您不必处理实体的状态。使用导航属性更新实体时最常见的问题是,当您可能希望出现相反的情况时,会收到重复的记录。假设你有这个简单的模型:

Using the Foreign key to update an entity is preferable over the navigation property, simple because you won't have to deal with the state of the entities. The most common problem with updating entities using navigation properties is getting duplicates records when you probably expect the contrary. Suppose you have this simple model:

public class Post
{
    public int Id {get; set;}
    public string Title {get; set;}

    [ForeignKey("CategoryId")]
    public Category Category {get; set;}

    public int CategoryId {get; set;}
}


public class Category
{
    public int Id {get; set;}
    public string Name {get; set;}
}

现在让我们假设你有一个控制器操作来更新一个帖子。认为View有ListBox列出所有类别,用户可以更改它。

Now let's suppose you have a controller action which updates a Post. Think that the View has a ListBox listing all categories and the user can change it.

PostController更新

[HttpPost]
public ActionResult UpdatePost(PostDTO, post)
{   
    //Retrived the chosen category using its own "repository" class
    Category newCategory = categoryRepository.Get(post.CategoryId); 

    //other validations here..  

    //Call method to update passing postDTO and the existing category
    postRepository.Update(post, newCategory)
}

现在,在您的 PostRepository 中,您可以这样做:

Now, in your PostRepository, you do something like this:

public void Update(PostDTO postDTO, Category category)
{
    using (var context = new ScreencastContext())
    {
    //Get the post in this context
      var post = context.Post.SingleOrDefault(x => x.Id == postDTO.Id);

      post.Name = postDTO.Name;
      //set other Post fields...

      //Set the new category to the post
      //this category already exists in the database and was retrieved by another "context"
      post.Category = category;

      context.Post.Attach(post);
      context.Entry(post).State - EntityState.Modified;

      context.SaveChanges();
    }
}

可能你会认为实体框架会赶上您的类别对象已经存在于数据库中,并且只会更新Post表中的外键ID。 错误
它实际上会创建一个新的类别,这是因为当您从另一个上下文检索到类别时,该上下文不会将其识别为图形的一部分,并且无法识别的实体具有默认状态已添加。所以当你调用SaveChanges时,它将创建一个新的类别。

Probably you would think Entity Framework would "catch up" that your Category object already exists in the database, and will only update the foreign key id in the Post table. Wrong. It will actually create a new Category, and that's because when you retrieved the Category from another context, this context doesn't recognize it as part of the graph and unrecognized entities have a default state of Added. So when you call SaveChanges it will create a new Category.

你可以自己管理实体的状态来解决这个问题,但是这可以变得非常复杂你可以很容易地结束了不少人奇怪的代码,没有人能理解。

You can manage the state of the entities by yourself to get around this problem, but this can get very complicated and you can easily ended up overwhelmed with a lot of weird code that no one can understand. That's when Foreign Keys come in handy.

上面的更新方法可以重写为:

The Update method above can be rewriten to something like this:

public void Update(PostDTO postDTO, Category category)
{
    using (var context = new ScreencastContext())
    {
      //Get the post in this context
      var post = context.Post.SingleOrDefault(x => x.Id == postDTO.Id);

      post.Name = postDTO.Name;
      //set other Post fields...

      //Set the new category to a post
      //this category already exists in the database and was retrived by another "context"
      post.CategoryId = category.Id;

      //This just prevent any accidental navigation property being set.
      post.Category = null;

      context.Post.Attach(post);
      context.Entry(post).State = EntityState.Modified;

      context.SaveChanges();
    }
}

这样你只更新Post表。一个新的类别将不会被创建,一切都将按预期的方式工作。

This way you update only the Post table. A new category won't be created and everything will work as expected.

这是我经常在自己的工作场所发现的东西,我一直都是指人Julie Lerman撰写的惊人的文章:

This is something that I found happening in my own workplace very often, and I always refer to people this amazing article written by Julie Lerman:

为什么实体框架将现有对象重新插入到我的数据库?

这篇关于在实体框架中使用外键更新实体和导航属性之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆