使用新密钥复制实体

时间:2014-10-21 15:15:22

标签: c# asp.net asp.net-mvc entity-framework

所以在使用Entity Framework的ASP.NET MVC应用程序中,我希望能够将现有实体(在这种情况下,PERS936AB_request_original)复制,更改一些数据,并将新实体保存到数据库。这是我现在拥有的:

var PERS936AB_request_original = db.PERS936AB.Single(r => r.ID == id);
var new_request = DataContractSerialization<PERS936AB>(PERS936AB_request_original);
new_request.Year = currentYear;
db.PERS936AB.AddObject(new_request);
db.SaveChanges();

我从MSDN Forum thread获得的DataContractSerialization方法。

private static T DataContractSerialization<T>(T obj)
{
    DataContractSerializer dcSer = new DataContractSerializer(obj.GetType());
    MemoryStream memoryStream = new MemoryStream();

    dcSer.WriteObject(memoryStream, obj);
    memoryStream.Position = 0;

    T newObject = (T)dcSer.ReadObject(memoryStream);
    return newObject;
}

当我完成所有这些操作时,我收到以下消息。这条消息很有意义,我只是不知道如何“重置”新实体并给它一个新密钥,而且我的搜索结果毫无结果。

  

ObjectStateManager中已存在具有相同键的对象。   ObjectStateManager无法跟踪具有相同对象的多个对象   键。

任何帮助都会很棒,谢谢!

2 个答案:

答案 0 :(得分:2)

问题是跟踪了原始对象,因此无法添加它的副本。但是没有必要跟踪原件,因为你没有更新它。所以你必须确保没有跟踪对象。同时,您不需要此序列化步骤。您只需修改原始对象并将其添加到上下文中即可。 EF会将其视为一个全新的实例,并忽略其当前的主键值:

db.ContextOptions.LazyLoadingEnabled = false;
db.PERS936AB.MergeOption = MergeOption.NoTracking;
var new_request = db.PERS936AB.Single(r => r.ID == id);
new_request.Year = currentYear;
db.PERS936AB.AddObject(new_request);
db.SaveChanges();

我确定禁用延迟加载:它可以防止无意中添加嵌套对象。

答案 1 :(得分:0)

您需要将ID更改为0. EF认为它们是完全相同的实体(即使年份不同),因为它会根据对象本身的ID进行检查。将其设置为0将告诉EF它是一个全新的实体。