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

Linq to sql Linq到sql,将原始实体复制到新实体并保存,linq-to-sql,Linq To Sql,我的情况是,我不能只更新数据库中的原始记录,而是创建一个新记录,从旧记录复制所有字段,并将更改应用到新记录。 (如果转换为代码,则类似于此) 这就产生了以下例外情况: Cannot add an entity that already exists. 是否可以在不手动复制每个字段的情况下使其工作?您可以使用反射来迭代属性并设置它们 foreach (var prop in original.GetType().GetProperties()) { prop.SetValue(

我的情况是,我不能只更新数据库中的原始记录,而是创建一个新记录,从旧记录复制所有字段,并将更改应用到新记录。 (如果转换为代码,则类似于此)

这就产生了以下例外情况:

Cannot add an entity that already exists.

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

您可以使用反射来迭代属性并设置它们

  foreach (var prop in original.GetType().GetProperties())
  {
     prop.SetValue(newTest, prop.GetValue(original,null), null);
  }
显然,这需要扩展,以减少出错的可能性,但这可能是一个良好的开端

与手动写入属性相比,这肯定会有一个较慢的运行时间,我可以想象。

这应该可以:

通用克隆()方法

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


您可能还想调查Plinko。它具有克隆、分离、附加、序列化为xml、序列化为二进制、多对多关系等功能。。。好吧,开箱即用,这样你就不必处理这些本来应该包括在第一位的功能


使用反射,可以轻松复制未生成的每个属性。这种方法可能性能不太好,但在紧要关头它会起作用

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;
}
公共静态T克隆(此T源)
{
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())
其中(p=>p.Attr!=null&&!p.Attr.IsDbGenerated);
foreach(以cols为单位的变量col)
col.Prop.SetValue(克隆,col.Prop.GetValue(源,null),null);
返回克隆;
}

如果您创建一个存储过程并将对象复制到其中,而不是在linq sql限制上浪费时间,可能会更好。您可以用sql语法轻松地处理错误和其他问题

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

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

你可以用

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

AutoMapper.Mapper.CreateMap()
//添加到db时,不映射id以停止冲突
.ForMember(a=>a.Id,a=>a.Ignore());
然后打电话:

var newObject = AutoMapper.Mapper.Map<MyObject>(oldObject);
var newObject=AutoMapper.Mapper.Map(oldObject);

唯一的问题是,如果克隆时有任何关联实体挂起原始实体,则在添加为newTest时,EntityKey仍然填充有原始键。@标记-当我实现类似功能时,我会加载()我正在克隆的对象的任何子实体,否则序列化程序将看不到它们,并将跳过它们。加载后,克隆对象工作正常,LINQ to SQL会自动插入新的子记录,新克隆的父记录的键位于.SubmitChanges()上。您所说的.Load()是什么意思?我正在对所有集合执行LoadWith以使其序列化,但克隆后一对一实体为空(即使设置了ID),我对LoadWith并不着迷。当我实现并运行此方法时,我得到:Message=“类型'mymodel.submodel'的对象图包含循环,如果禁用引用跟踪,则无法序列化。" ... 如何解决此问题?@guiomie-这通常意味着对象中有循环引用。
ColumnAttribute
是否应该从
System.ComponentModel.DataAnnotations.Schema
System.Data.Linq.Mapping.DataAttribute
?虽然Automapper的实现已经过时,但这是最好的方法为了我。我建议任何想用这个来查看AutoMapper页面的人。
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;
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;
}
AutoMapper.Mapper.CreateMap<MyObject, MyObject>()
// don't map the id to stop conflicts when adding into db
    .ForMember(a => a.Id, a => a.Ignore()); 
var newObject = AutoMapper.Mapper.Map<MyObject>(oldObject);