使用另一个对象更新 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() 就会更新实体而不是失败。