Linq to sql,将原始实体复制到新的实体并保存

shk*_*per 25 linq-to-sql

我有一种情况,当我不能更新数据库中的原始记录,而是创建一个新记录,从旧复制所有字段并将更改应用于新的.(如果翻译成代码,这样的东西)

var original = from _orig in context.Test where _orig.id == 5 select _orig;
Test newTest = new Test();
newTest = original;
newTest.id = 0;
context.Test.InsertOnSubmit(newTest);
context.SubmitChanges();
original.parent_id = newTest.id;
original.isActive = 0;
Run Code Online (Sandbox Code Playgroud)

这给出了以下例外:

Cannot add an entity that already exists.
Run Code Online (Sandbox Code Playgroud)

是否可以在不手动复制每个字段的情况下使其工作?

Lan*_*ney 30

这应该工作:

通用克隆()方法

此方法将通过序列化来创建任何对象的完整克隆.最初的想法来自这里这里.

/// <summary>
/// Clones any object and returns the new cloned object.
/// </summary>
/// <typeparam name="T">The type of object.</typeparam>
/// <param name="source">The original object.</param>
/// <returns>The clone of the object.</returns>
public static T Clone<T>(this T source) {
    var dcs = new DataContractSerializer(typeof(T));
    using(var ms = new System.IO.MemoryStream()) {
        dcs.WriteObject(ms, source);
        ms.Seek(0, System.IO.SeekOrigin.Begin);
        return (T)dcs.ReadObject(ms);
    }
}
Run Code Online (Sandbox Code Playgroud)

你的代码示例

现在借助上面的扩展方法,如果稍微调整一下,你的代码应该可以工作:

var original = from _orig in context.Test where _orig.id == 5 select _orig;
Test newTest = original.Clone();
newTest.id = 0;
context.Test.InsertOnSubmit(newTest);
context.SubmitChanges();
original.parent_id = newTest.id;
original.isActive = 0;
Run Code Online (Sandbox Code Playgroud)


dav*_*v_i 7

是否可以在不手动复制每个字段的情况下使其工作?

是 - 不要手动复制每个字段:

您可以使用AutoMapper.

在某处设置(在程序启动时调用一次):

AutoMapper.Mapper.CreateMap<MyObject, MyObject>()
// don't map the id to stop conflicts when adding into db
    .ForMember(a => a.Id, a => a.Ignore()); 
Run Code Online (Sandbox Code Playgroud)

然后打电话:

var newObject = AutoMapper.Mapper.Map<MyObject>(oldObject);
Run Code Online (Sandbox Code Playgroud)


bra*_*rad 5

使用Reflection,您可以轻松复制非DbGenerated的每个属性.这种方法可能不是很有效,但它可以在紧要关头工作.

public static T Clone<T>(this T source)
{
    var clone = (T)Activator.CreateInstance(typeof(T));
    var cols = typeof(T).GetProperties()
        .Select(p => new { Prop = p, Attr = (ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute), true).SingleOrDefault() })
        .Where(p => p.Attr != null && !p.Attr.IsDbGenerated);
    foreach (var col in cols)
        col.Prop.SetValue(clone, col.Prop.GetValue(source, null), null);
    return clone;
}
Run Code Online (Sandbox Code Playgroud)