EF 6:动态复制DbSet的条目

时间:2017-08-24 09:42:44

标签: c# entity-framework linq

初始情况:

选择几个要复制的条目:

var violations = entities.StagingViolation.Where(entry => entry.ViolationCode == processingEngineViolation.ViolationCode).ToList();

通过" StagingViolation"的属性使用反射到迭代器。对象并复制所有属性。只有属性" ProcessingId" (类型:Guid)应该分配一个新值:

entities.StagingViolation.AddRange(violations.Select(violation => {
       var newViolation = new StagingViolation();

       typeof(StagingViolation).GetProperties()
              .ToList()
              .ForEach(property => { 
                    typeof(StagingViolation).GetProperty(property.Name).SetValue(newViolation, property.GetValue(violation, null));
              });

         newViolation.ProcessingId = newProcessingId;

         return newViolation;
}));

entities.SaveChanges();

假设 StagingViolation 类如下所示:

public class StagingViolation {
    public Guid ProcessingId { get; set; }
    public string ViolationCode { get; set; }
    public string ViolationDetailCode { get; set; }
}

预期结果:

原始 StagingViolation 对象如下所示:

ProcessingId = 'B4E3D49F-B8E3-4988-AAF2-42259059FA03'
ViolationCode = 'ABC'
ViolationDetailCode = 'ABC.123'

已复制的 StagingViolation 应如下所示:

var newProcessingId = 'F8028E92-7234-4590-8EAB-170DE5B5E6DA'

--------------------

ProcessingId = newProcessingId 
ViolationCode = 'ABC'
ViolationDetailCode = 'ABC.123'

但复制的对象确实包含相同的" ProcessingId"作为最终的原始对象。有人知道为什么吗?

编辑1:

此整个功能包含在以下上下文中:

private void CopyViolations(OverrideCodeInput violationOverrideCode, Guid newProcessingId) {
 ...
}

我通过迭代调试并发现" newProcessingId"包含正确的值,newViolation.ProcessingId = newProcessingId也正确执行。但最后,当我在entities.SaveChanges处使用断点时,该集合确实添加了新条目,但它们包含旧的" ProcessingId"。

仅供参考:" ProcessingId"是主键的一部分。这就是为什么我在SaveChanges()处获得主要密钥违规的例外情况。

1 个答案:

答案 0 :(得分:1)

由于IvanStoev和haim770的帮助,我通过将 NavigationProperties 排除在复制到新对象之外来解决了我的问题。因此,在迭代 StagingViolation 的属性之前,我使用扩展来检查 PropertyType property.PropertyType.IsSimpleType()

entities.StagingViolation.AddRange(violations.Select(violation => {
        var newViolation = new StagingViolation();

        typeof(StagingViolation).GetProperties().Where(property => property.PropertyType.IsSimpleType())
                    .ToList()
                    .ForEach(property => {
                        typeof(StagingViolation).GetProperty(property.Name).SetValue(newViolation, property.GetValue(violation, null));
    });

    newViolation.ProcessingId = newProcessingId;

    return newViolation;
}));


public static class TypeExtension {
    public static bool IsSimpleType(this Type type) {
        while (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
            type = type.GetGenericArguments()[0];
        }

        return type.IsValueType || type.IsPrimitive || new[] { typeof(string), typeof(decimal), typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), typeof(Guid) }.Contains(type) || Convert.GetTypeCode(type) != TypeCode.Object;          
    }
}