EF Core 在编辑时不更新某些字段
EF Core do not update some of the fields when editing
能否请您告诉我是否可以使用 EF Core 从编辑记录中排除某些列。
语境:
我有一个 table ,其中有一个文件存储为字节数组,但是在编辑记录时,我得到空值,我想通过对数据库的额外查询来解决这个问题,我在数据库中使用旧字段并将其插入到编辑过的文件中,但在我看来这是一个笨拙的解决方案。
我会加:
有一天您仍然需要编辑字段,但不是典型的编辑。
public async Task<IActionResult> Edit(int id, [Bind("id,Name,Price,Minimum_Pages,Requirements,Responsible,Start_Registration,Start_Conference,ResponsibleID,File,File_Name,File_Descriptor,Priority")] Registry_Conference registry_Conference)
{
if (id != registry_Conference.id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(registry_Conference);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!Registry_ConferenceExists(registry_Conference.id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View("~/Views/NPR_Module/Registry/Registry_Conference/Edit.cshtml", registry_Conference);
}
您示例中的“拐杖”期望传入的值是一个实体。它是使用 Entity 类型声明的,但它不是一个实体,它甚至不是一个分离的实体。它有点反序列化 JSON 看起来像一个实体。
当您调用 Update
时,EF 需要一个完整的独立实体。你不能提供它,所以简单的答案是你不能可靠地使用 Update
作为拐杖来获取所需的数据。当你给它反序列化 JSON 时,实体相似对象将只有传递到调用中的数据。对于非常简单的对象,在这些对象中,您可以将所有内容传入和传出您的客户端,您可以避免这样做,但这确实会带来意外篡改您不希望更改的数据的风险。
完成所需任务的最简单方法是使用 Automapper。最基本的:
var mapper = new MapperConfiguration(cfg => {
cfg.CreateMap<Registry_Conference, Registry_Conference>()
.ForMemeber(x => x.FileData, opt => opt.Ignore())
// Add any other properties that should not be copied...
}).CreateMapper();
var dataRegistryConference = _context.Registry_Conferences.Single(x => x.Id == registry_Conference.Id);
// TODO: Check Row Version here.
// As well as other validations.
mapper.Map(registry_Conference, dataRegistryConference);
_context.SaveChanges();
或者,您可以手动将传入数据中的允许值复制到实时数据中。反对这种方法的典型 question/argument 是“我想避免对数据库的额外调用”。对此的简单回答是您真的不想,或者至少有充分的理由检查数据库。
// Check Row Version
如果您正在跟踪行修改跟踪的行版本标记。如果其他人修改了此行,这有助于防止陈旧数据被覆盖,因为调用者传回修改后的对象已经获取了他们所做更改所基于的数据副本。您应该进行的其他检查包括 ownership/permissions 之类的内容。你的方法最终会传递一个你应该确保存在的 ID,处理过时的数据,并验证当前用户可以并且应该被允许在当前状态下更新它。 (即这个用户是否有权访问 see/edit 它?数据是否处于允许编辑的状态?等)为此,您应该始终检查现有数据状态作为真实来源,永远不要相信传递的内容英寸
使用 Automapper 或手动复制 Update
的另一个好处是,如果任何值实际发生变化,EF 只会生成 UPDATE
SQL 语句,并且仅针对改变的值。使用 Update
将为 所有 列执行 UPDATE
SQL,无论它们是否更改,更新行版本和触发触发器等
更好的做法是避免将传入的数据屏蔽为实体,并声明只包含应编辑的数据的视图模型。这样您就不需要在映射器中配置任何 Ignore()
设置。如果以后您有可以接受实体的通用代码并且您想要从这样的地方调用该代码,它也可以避免混淆。接受实体的代码应始终获得完整或可完成的实体,其中此方法仅提供不完整的 shell 实体。
能否请您告诉我是否可以使用 EF Core 从编辑记录中排除某些列。 语境: 我有一个 table ,其中有一个文件存储为字节数组,但是在编辑记录时,我得到空值,我想通过对数据库的额外查询来解决这个问题,我在数据库中使用旧字段并将其插入到编辑过的文件中,但在我看来这是一个笨拙的解决方案。 我会加: 有一天您仍然需要编辑字段,但不是典型的编辑。
public async Task<IActionResult> Edit(int id, [Bind("id,Name,Price,Minimum_Pages,Requirements,Responsible,Start_Registration,Start_Conference,ResponsibleID,File,File_Name,File_Descriptor,Priority")] Registry_Conference registry_Conference)
{
if (id != registry_Conference.id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(registry_Conference);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!Registry_ConferenceExists(registry_Conference.id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View("~/Views/NPR_Module/Registry/Registry_Conference/Edit.cshtml", registry_Conference);
}
您示例中的“拐杖”期望传入的值是一个实体。它是使用 Entity 类型声明的,但它不是一个实体,它甚至不是一个分离的实体。它有点反序列化 JSON 看起来像一个实体。
当您调用 Update
时,EF 需要一个完整的独立实体。你不能提供它,所以简单的答案是你不能可靠地使用 Update
作为拐杖来获取所需的数据。当你给它反序列化 JSON 时,实体相似对象将只有传递到调用中的数据。对于非常简单的对象,在这些对象中,您可以将所有内容传入和传出您的客户端,您可以避免这样做,但这确实会带来意外篡改您不希望更改的数据的风险。
完成所需任务的最简单方法是使用 Automapper。最基本的:
var mapper = new MapperConfiguration(cfg => {
cfg.CreateMap<Registry_Conference, Registry_Conference>()
.ForMemeber(x => x.FileData, opt => opt.Ignore())
// Add any other properties that should not be copied...
}).CreateMapper();
var dataRegistryConference = _context.Registry_Conferences.Single(x => x.Id == registry_Conference.Id);
// TODO: Check Row Version here.
// As well as other validations.
mapper.Map(registry_Conference, dataRegistryConference);
_context.SaveChanges();
或者,您可以手动将传入数据中的允许值复制到实时数据中。反对这种方法的典型 question/argument 是“我想避免对数据库的额外调用”。对此的简单回答是您真的不想,或者至少有充分的理由检查数据库。
// Check Row Version
如果您正在跟踪行修改跟踪的行版本标记。如果其他人修改了此行,这有助于防止陈旧数据被覆盖,因为调用者传回修改后的对象已经获取了他们所做更改所基于的数据副本。您应该进行的其他检查包括 ownership/permissions 之类的内容。你的方法最终会传递一个你应该确保存在的 ID,处理过时的数据,并验证当前用户可以并且应该被允许在当前状态下更新它。 (即这个用户是否有权访问 see/edit 它?数据是否处于允许编辑的状态?等)为此,您应该始终检查现有数据状态作为真实来源,永远不要相信传递的内容英寸
使用 Automapper 或手动复制 Update
的另一个好处是,如果任何值实际发生变化,EF 只会生成 UPDATE
SQL 语句,并且仅针对改变的值。使用 Update
将为 所有 列执行 UPDATE
SQL,无论它们是否更改,更新行版本和触发触发器等
更好的做法是避免将传入的数据屏蔽为实体,并声明只包含应编辑的数据的视图模型。这样您就不需要在映射器中配置任何 Ignore()
设置。如果以后您有可以接受实体的通用代码并且您想要从这样的地方调用该代码,它也可以避免混淆。接受实体的代码应始终获得完整或可完成的实体,其中此方法仅提供不完整的 shell 实体。