我有以下代码
var dbContext = Setup.ConfigureDBContext();
var wo = await dbContext.WorkOrders.Where(x => x.WorkOrderID == 88).SingleOrDefaultAsync();
var t = wo.Confidence;
wo.ModifiedDateTime = DateTime.UtcNow;
wo.Confidence = t;
await dbContext.SaveChangesAsync();
在上述查询中,我分配了相同的Confidence
,但更改了ModifiedDateTime
EF生成以下SQL
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [WorkOrders] SET [ModifiedDateTime] = @p0
WHERE [WorkOrderID] = @p1 AND [VersionStamp] = @p2;
SELECT [VersionStamp]
FROM [WorkOrders]
WHERE @@ROWCOUNT = 1 AND [WorkOrderID] = @p1;
',N'@p1 int,@p0 datetime,@p2 varbinary(8)',@p1=88,@p0='2019-10-09 15:33:06.343',@p2=0x0000000000582A52
请注意,EF在更新语句中不包括Confidence
列。我假设EF必须将原始值与新值进行比较,如果有更改,则仅在update语句中包括这些列。
那是正确的假设吗?
我问这个问题是因为WorkOrder
表也有4个nvarchar(max)列。这些列中的数据是长字符串。如果我的假设是正确的,那么EF还必须比较这4列以确定这些列是否需要包含在更新查询中。这样的比较会比较慢,并且可能会导致性能下降。然后,我可以仅为这4列创建单独的附属表。
答案 0 :(得分:0)
上下文具有内部更改跟踪器,顾名思义,该跟踪器跟踪对实体所做的更改。它不是在比较数据库中的内容,只是在注意那些已在代码中修改了其值的属性。如果仅更改单个或少数几个属性,则EF会发出一条update语句,该语句仅包含已修改属性的列,但并非以智能方式进行。换句话说,如果您使用以前拥有的值修改属性(无论是显式还是通过诸如AutoMapper之类的库之类的自动方式)修改的属性,即使实际值未更改,该属性也将在更新语句中包括该列。
答案 1 :(得分:0)
您的第一个实体是通过上下文获取的,因此默认情况下上下文会立即开始对其进行跟踪,这意味着您检索到的任何实体都将连同其原始值的副本一起存储在DbContext中。当您更改跟踪实体的属性值时,上下文会将实体的EntityState
更改为Modified
,并且ChangeTracker会记录旧属性值和新属性值。调用SaveChanges
时,数据库会生成并执行一条UPDATE语句,因为ChangeTracker会跟踪已修改的属性,因此上下文将发出一条SQL语句,该语句仅更新那些已更改的属性,它将对其进行比较。并使用其原始值来确定更新后的属性。
如果您担心特定的列,则可以禁用查询时跟踪:
var item = _context.Employees.Where(x=>x.ID==1).AsNoTracking().FirstOrDefault();
然后告诉上下文您要修改的属性,上下文将发出一条无需比较即可更新的SQL语句:
item.Name = "213213";
_context.Attach(item).Property(x => x.Name).IsModified = true;
_context.SaveChanges();