DbSet.Attach()和DbSet.Update()之间标记已修改属性的差异 [英] Differences in marking modified properties between DbSet.Attach() and DbSet.Update()

查看:184
本文介绍了DbSet.Attach()和DbSet.Update()之间标记已修改属性的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个Person类(具有Id和Age的属性),假设我们需要将一个id为1的人的Age从29更改为30,并且我使用 DbSet。 Update() DbSet.Attach()

let's say we have a Person class(with properties of Id and Age), let's say we need to change the Age of a person whose id is 1 from 29 to 30, and I use DbSet.Update() and DbSet.Attach() respectively:

Person p = new Person(){ Id = 1 }  
var entity = context.Persons.Update(p);
p.Age = 30;

Console.WriteLine("entity state:" + entity.State);
foreach (var modifiedProperty in entity.Properties.Where(p => p.IsModified))
{
   Console.Write($"The {modifiedProperty.Metadata.Name} property is marked as modified,");
}
context.SaveChanges();

输出:


实体状态:已修改。

entity state:Modified.

Age属性标记为已修改,Name属性标记为已修改*

The Age property is marked as modified,The Name property is marked as modified*

这是预期结果,但是如果我使用 Attach()作为

which is expected result, but if I use Attach() as

Person p = new Person(){ Id = 1 }  
var entity = context.Persons.Attach(p);
p.Age = 30;

Console.WriteLine("entity state:" + entity.State);
foreach (var modifiedProperty in entity.Properties.Where(p => p.IsModified))
{
   Console.Write($"The {modifiedProperty.Metadata.Name} property is marked as modified,");
}
context.SaveChanges();

输出:


实体状态:不变。

entity state:Unchanged.

之后没有任何更改,因为没有属性被标识为已修改,但是我以与Update()中相同的方式更改了Age属性方法,为什么 Attach()无法识别修改后的属性?如果 Attach()无法识别修改后的属性,为什么它仍会向数据库生成正确的更新sql语句?

and nothing after, since no properties has been identified as modified, but I changed the Age property the same way as in Update() method, why Attach() cannot identify modified properties? if Attach() cannot identify modified properties, how come it still generate the correct update sql statement to database?

推荐答案

您非常混淆 sql服务器中的内容上下文缓存中的内容。 DbContext缓存实体并跟踪它们,因此它知道在调用 SaveChanges()时该怎么做。如果实体在缓存中不存在,则由开发人员自行决定帮助框架确定正确的逻辑

You are very much confusing what is in sql server with what is in the context cache. The DbContext caches entities and tracks them so it knows what to do when SaveChanges() is called. If the entity does not exist in the cache, it is up to the developer to help entity-framework determine the correct logic.

DbSet.Update(TEntity)方法


开始跟踪处于Modified状态的给定实体,以便将其更新为

Begins tracking the given entity in the Modified state such that it will be updated in the database when SaveChanges() is called.

DbSet.Attach(TEntity)方法


开始以不变状态跟踪给定实体,这样在调用SaveChanges()时将不执行任何操作。

Begins tracking the given entity in the Unchanged state such that no operation will be performed when SaveChanges() is called.

到您的观点:


但是我改变了他的Age属性与Update()方法中的方法相同。

but I changed the Age property the same way as in Update() method

是的,但这并不会改变其附加方式。事件的顺序非常重要。在以下示例中,我们将年龄更改为31,然后将附加到实体到实体框架上下文。它不知道您已更改,更改发生时它没有跟踪(记录不会更改为31):

Yes you did, but that does not change how you attached it. Order of events is very important. In the following example, we change Age to 31 before we attach the entity to the Entity Framework Context. It does not know you changed it was not tracking it at the time the change occurred (record will NOT change to 31):

using (var context = new EntityContext())
{
    p.Age = 31;
    context.Persons.Attach(p);
    context.SaveChanges();
}




如果Attach()无法识别修改后的属性,为什么我们仍会生成正确的更新sql语句到数据库

if Attach() cannot identify modified properties, how come it still generate the correct update sql statement to database

如果我们更改事件顺序以附加实体 我们更改一个值,然后Entity Framework可以检测到更改并将其保存到数据库(记录将更改为32):

If we change the order of events to Attach the entity before we change a values, then Entity Framework can detect the change an save it to the DB (record will CHANGE to 32):

using (var context = new EntityContext())
{
    context.Persons.Attach(p);
    p.Age = 32;
    context.SaveChanges();
}

所有工作示例:

DotNetFiddle核心示例

// Entity Framework Extensions
// Doc: https://entityframework-extensions.net/context-factory

// @nuget: Microsoft.EntityFrameworkCore
// nuget: Z.EntityFramework.Extensions.EFCore
// @nuget: Microsoft.EntityFrameworkCore.SqlServer
// @nuget: Microsoft.Extensions.Logging

using System;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.Extensions.Logging;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var p = new Person();
        using (var context = new EntityContext())
        {
            context.Database.EnsureCreated();
            p.Age = 29;
            context.Persons.Add(p);
            context.SaveChanges();
        }

        using (var context = new EntityContext())
        {
            Console.WriteLine("Created Person Age 29");
            FiddleHelper.WriteTable("Student", context.Persons.ToList());
        }

        using (var context = new EntityContext())
        {
            p.Age = 30;
            context.Persons.Update(p);
            context.SaveChanges();
        }

        using (var context = new EntityContext())
        {
            Console.WriteLine("Update Person Age 30");
            FiddleHelper.WriteTable("Student", context.Persons.ToList());
        }

        using (var context = new EntityContext())
        {
            p.Age = 31;
            context.Persons.Attach(p);
            context.SaveChanges();
        }

        using (var context = new EntityContext())
        {
            Console.WriteLine("Change Person to 31, THEN Attach");
            FiddleHelper.WriteTable("Student", context.Persons.ToList());
        }

        using (var context = new EntityContext())
        {
            context.Persons.Attach(p);
            p.Age = 32;
            context.SaveChanges();
        }

        using (var context = new EntityContext())
        {
            Console.WriteLine("Attach THEN Change Person to 32");
            FiddleHelper.WriteTable("Student", context.Persons.ToList());
        }

    }

    public class EntityContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var connectionString = FiddleHelper.GetConnectionStringSqlServer();
            optionsBuilder.UseSqlServer(connectionString);
        }
        public DbSet<Person> Persons { get; set; }
    }

    public class Person
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }
        public int Age { get; set; }
        public string Name { get; set; }
    }
}

这篇关于DbSet.Attach()和DbSet.Update()之间标记已修改属性的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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