为啥 context.SaveChanges() 会更新表中的每一行?

Posted

技术标签:

【中文标题】为啥 context.SaveChanges() 会更新表中的每一行?【英文标题】:Why does context.SaveChanges() update every row in the table?为什么 context.SaveChanges() 会更新表中的每一行? 【发布时间】:2019-05-29 21:45:06 【问题描述】:

我使用 C# 和 Entity Framework 6 (EF6) 编写了一些代码 与 mysql。 IDE 是 Visual Studio 2019 预览版。

我安装了这些软件包:

<packages>
  <package id="EntityFramework" version="6.2.0" targetFramework="net461" />
  <package id="MySql.Data" version="6.10.8" targetFramework="net461" />
  <package id="MySql.Data.Entity" version="6.10.8" targetFramework="net461" />
</packages>

插入和选择工作正常 但是更新是有线的。

我在tbx_CarId 中输入了一些数字(例如 2 或 100) 我希望 EF6 只更新一行, 但它会更新表格中的每个低点。

private void btn_update_Click(object sender, EventArgs e)

    using (MySqlConnection connection = new MySqlConnection(connectionString))
    
        connection.Open();

        using (Parking context = new Parking(connection, false))
        
            context.Database.Log = (string message) =>  Console.WriteLine(message); ;

            int targetId = Int32.Parse(tbx_CarId.Text);
            var blogs = from b in context.Cars
                        where b.CarId == targetId
                        select b;
            Car item = blogs.Single();
            item.Model = tbx_NewModel.Text;
            int numOfSavedLows = context.SaveChanges();
            Console.WriteLine("numOfSavedLows: " + numOfSavedLows.ToString());
        
    

context.SaveChanges() 方法总是返回一个精确的数字,1, 并在控制台窗口上打印“numOfSavedLows: 1”。

但每当我执行该方法时,每一行都会更改。

此外,EF6 的记录器会在控制台上这样写:

Started transaction at 2019-01-03 오후 6:47:59 +09:00
`Car_Update`
-- CarId: '2' (Type = Int32, IsNullable = false)
-- Model: 'new value of the model' (Type = String, IsNullable = false, Size = 5)
-- Year: '2013' (Type = Int32, IsNullable = false)
-- Manufacturer: 'Dodge' (Type = String, IsNullable = false, Size = 5)
-- Executing at 2019-01-03 오후 6:47:59 +09:00
-- Completed in 6 ms with result: 16

Committed transaction at 2019-01-03 오후 6:47:59 +09:00
Disposed transaction at 2019-01-03 오후 6:47:59 +09:00

请看-- Completed in 6 ms with result: 16这一行 数字(在本例中为 16)是Car 表中每一行的计数。

为什么 EF6 每次低更新? 我该如何解决?

其余代码在这里:

[DbConfigurationType(typeof(MySqlEFConfiguration))]
class Parking : DbContext

    public DbSet<Car> Cars  get; set; 

    public Parking()
      : base()
    
        // constructor is empty
    

    // Constructor to use on a DbConnection that is already opened
    public Parking(DbConnection existingConnection, bool contextOwnsConnection)
      : base(existingConnection, contextOwnsConnection)
    
        // constructor is empty
    

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Car>().MapToStoredProcedures();
    

class Car

    public int CarId  get; set; 
    public string Model  get; set; 
    public int Year  get; set; 
    public string Manufacturer  get; set; 

大部分代码来自这里: https://dev.mysql.com/doc/connectors/en/connector-net-entityframework60.html

更新 1: 表Cars 看起来像 this (架构和表是EF6自动生成的)

更新 2: 行的值是这样的: Before 和 After(参数为 8,'新值')

【问题讨论】:

您确定更新了 16 行吗?也许表包含索引,并且它被重建了?有没有用 profiler 查看生成的 sql 代码? 只有当 CarId 不是唯一的并且有 16 条记录具有 CarId == 2 时才会发生这种情况。 您是否检查了 DbContext 的 ChangeTracker 中的实体状态?所有这些都应该等于 EntityState.Unchanged,除了您更改的实体。 当您运行数据库跟踪(或使用hibernatingrhinos.com/products/efprof)查看发送到数据库的确切命令时,提交的是什么? 你能进入数据库找到Car_Update过程吗? 【参考方案1】:

Context.Savechanges() 查找所有 dbsets(entities) 中的所有更改并将所有更改提交到数据库中,这是 Entity 框架中的一个抽奖。

【讨论】:

不过,他只换了一排。 DbContext 的 ChangeTracker 应该包含所有元素,但大多数元素的 State 应该等于 EntityState.Unchanged。【参考方案2】:

我猜您的实体没有定义主列。 这样,Entity Framework 无法选择表中的相关数据到您的实体,并更新“一切”(每个条目与主键定义匹配)满足条件的每一行。 您需要添加类似

的内容
[Key, Column("Car_ID_IN_DB"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CarId get; set;

到您的CarId 上的建模Cars 表(您没有显示此定义)

这仅在您使用 CodeFirst 时有效,如果您使用 DbFirst,您应该检查生成的 Cars 实体是否正确建模并且您是否在数据库中建模了主键。

【讨论】:

但是表Cars有一个主键...CarId列是主键。看一下这个。 i.stack.imgur.com/x1cle.png【参考方案3】:

正如official EF6 GitHub 中所建议的,

删除我的 DbContext 中的 MapToStoredProcedure 解决了这个问题。

我会告诉您尝试删除“MapToStoredProcedures()”代码,看看您是否得到任何不同的结果。

【讨论】:

以上是关于为啥 context.SaveChanges() 会更新表中的每一行?的主要内容,如果未能解决你的问题,请参考以下文章

DB ConnectionState = Open 但 context.SaveChanges 抛出“连接中断”异常

ef保存文件到指定目录

StopWatch

如何使用实体框架通过 id 删除对象

EF LINQ 查询性能优化

无法更新EF6中的实体?