使用另一个对象更新 EF Core 中的记录
Update a record in EF Core with another object
我在数据库中有许多加密的列。我可以使用 EF Core 6 从数据库中提取记录,我可以将记录传递给解密例程,但我需要使用未加密的值更新记录。
解密例程如下:
public Subject DecryptSubjects(Subject decryptSubject, List<string> EncryptedColumns)
{
if (decryptSubject == null)
{
return null;
}
var decryptedProperty = decryptSubject.GetType().GetProperty("Decrypted");
if (decryptedProperty != null)
{
bool? value = (bool?)decryptedProperty.GetValue(decryptSubject, null);
if (value != null)
{
if (value == true)
{
return decryptSubject;
}
}
}
foreach (string name in EncryptedColumns)
{
var property = decryptSubject.GetType().GetProperty(name);
if (property != null)
{
var value = property.GetValue(decryptSubject, null);
if (value != null)
{
property.SetValue(decryptSubject, Decrypt(value.ToString()), null);
}
}
}
if (decryptedProperty != null)
{
decryptedProperty.SetValue(decryptSubject, true, null);
}
return decryptSubject;
}
这会很好地返回解密值。
下面是对这个例程的调用:
var subjects = context.Subjects.ToList();
foreach (var subject in subjects)
{
// decrypt each subject and then update them in the database
var decryptedSubject = encrypt.DecryptSubjects(subject, subjectCols);
}
获得 decryptedSubject
后,我想更新数据库中的记录。有没有比将主题对象上的每个 属性 设置为 decryptedSubject
中的解密值更好的方法喜欢这样:
...
subject.FirstName = decrytpedSubject.FirstName;
subject.LastName = decrytedSubject.LastName;
...
一种快速简便的方法是使用 Automapper 为 CreateMap<Subject, Subject>()
设置映射器配置,并排除您绝对不想允许被覆盖的字段。从那里您可以使用 little-documented .Map(decryptedSubject, subject)
方法来复制值。
Update
也可以工作,但您需要断言 DbContext 尚未跟踪同一记录的实例。这意味着检查 context.Subjects.Local
任何现有的跟踪引用并分离它们,或者如果一个已经被跟踪则使用跨复制方法。否则,您将在 Update
调用中遇到异常。如果该引用作为较大操作的一部分进行跟踪,而该引用与可能在此操作期间更新的另一个实体相关联,则分离现有的跟踪引用可能会产生负面影响。flow-on。
Update
也会覆盖所有内容。 (包括 FK 和其他您可能不允许更改的东西)它还会为 all 列生成一个 UPDATE
SQL 语句,无论任何值是否发生变化不是,使用 Automapper Map
或手动复制方法只会为实际更改的值生成并执行 UPDATE
语句,如果有任何值实际更改的话。这也不会添加验证以确保您打算更新的记录实际存在于数据库中,其中加载现有实体并使用 Map()
复制值或手动 pre-assert 实际上有一个如果这是较大操作的一部分,则只要可能发生 SaveChanges()
就会更新实体而不是失败。
我在数据库中有许多加密的列。我可以使用 EF Core 6 从数据库中提取记录,我可以将记录传递给解密例程,但我需要使用未加密的值更新记录。
解密例程如下:
public Subject DecryptSubjects(Subject decryptSubject, List<string> EncryptedColumns)
{
if (decryptSubject == null)
{
return null;
}
var decryptedProperty = decryptSubject.GetType().GetProperty("Decrypted");
if (decryptedProperty != null)
{
bool? value = (bool?)decryptedProperty.GetValue(decryptSubject, null);
if (value != null)
{
if (value == true)
{
return decryptSubject;
}
}
}
foreach (string name in EncryptedColumns)
{
var property = decryptSubject.GetType().GetProperty(name);
if (property != null)
{
var value = property.GetValue(decryptSubject, null);
if (value != null)
{
property.SetValue(decryptSubject, Decrypt(value.ToString()), null);
}
}
}
if (decryptedProperty != null)
{
decryptedProperty.SetValue(decryptSubject, true, null);
}
return decryptSubject;
}
这会很好地返回解密值。
下面是对这个例程的调用:
var subjects = context.Subjects.ToList();
foreach (var subject in subjects)
{
// decrypt each subject and then update them in the database
var decryptedSubject = encrypt.DecryptSubjects(subject, subjectCols);
}
获得 decryptedSubject
后,我想更新数据库中的记录。有没有比将主题对象上的每个 属性 设置为 decryptedSubject
中的解密值更好的方法喜欢这样:
...
subject.FirstName = decrytpedSubject.FirstName;
subject.LastName = decrytedSubject.LastName;
...
一种快速简便的方法是使用 Automapper 为 CreateMap<Subject, Subject>()
设置映射器配置,并排除您绝对不想允许被覆盖的字段。从那里您可以使用 little-documented .Map(decryptedSubject, subject)
方法来复制值。
Update
也可以工作,但您需要断言 DbContext 尚未跟踪同一记录的实例。这意味着检查 context.Subjects.Local
任何现有的跟踪引用并分离它们,或者如果一个已经被跟踪则使用跨复制方法。否则,您将在 Update
调用中遇到异常。如果该引用作为较大操作的一部分进行跟踪,而该引用与可能在此操作期间更新的另一个实体相关联,则分离现有的跟踪引用可能会产生负面影响。flow-on。
Update
也会覆盖所有内容。 (包括 FK 和其他您可能不允许更改的东西)它还会为 all 列生成一个 UPDATE
SQL 语句,无论任何值是否发生变化不是,使用 Automapper Map
或手动复制方法只会为实际更改的值生成并执行 UPDATE
语句,如果有任何值实际更改的话。这也不会添加验证以确保您打算更新的记录实际存在于数据库中,其中加载现有实体并使用 Map()
复制值或手动 pre-assert 实际上有一个如果这是较大操作的一部分,则只要可能发生 SaveChanges()
就会更新实体而不是失败。