为啥 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() 会更新表中的每一行?的主要内容,如果未能解决你的问题,请参考以下文章