我具有以下结构,并且正在使用Entity Framework 6.2:
public class MainModel
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public ModelB ModelB { get; set; }
public ModelC ModelC { get; set; }
}
public class ModelB
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public Account Account { get; set; }
}
public class ModelC
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public Account Account { get; set; }
}
public class Account
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long Id { get; set; }
public string Description { get; set; }
}
我不希望SQL自动分配PK,因为这些实体已经具有唯一的ID(例如,只有1个帐户的ID为2,依此类推。)
当我尝试运行以下命令时,出现私钥冲突无法在对象dbo.Account
中插入重复密钥。重复的键值为(2)。
var context = new MyContext();
myOrders.ToList().ForEach(p =>
{
context.MyOrders.AddOrUpdate(p);
});
context.SaveChanges();
我尝试过AsNoTracking()
并将EntityState
设置为Modified
(如果已在表中找到它的话)。
这是填充myOrders的JSON数据。 myOrders是一个列表
[ {
"MainModel": {
"Id": 100,
"ModelB": {
"Id": 1,
"Account": {
"Id": 2,
"Description":"This is a test account"
}
},
"ModelC": {
"Id": 1,
"Account": {
"Id": 2,
"Description":"This is a test account"
}
}
}
},
{
"MainModel": {
"Id": 200,
"ModelB": {
"Id": 5,
"Account": {
"Id": 2,
"Description":"This is a test account"
},
}
"ModelC": {
"Id": 6,
"Account": {
"Id": 2,
"Description":"This is a test account"
}
}
}
}
}
]
有什么想法吗?
答案 0 :(得分:0)
首先,如果这是应用程序代码而不是迁移/测试设置,则应避免使用AddOrUpdate。它不打算用于一般的插入或更新方案。作为一般规则,我完全不建议传递实体。实体代表您的领域,而不是您的模型。模型类(或ViewModels)应该是简单的,可序列化的POCO类,其中仅包含视图需要使用的信息。传递实体会导致重新连接的复杂性,潜在延迟负载的性能问题以及您经常查询和传递不必要数据的简单事实,以及传递更多信息(在您的情况下值得信任)的安全性问题,这意味着破坏数据源相对容易。即通过您可能不打算更改客户端的调试工具来修改实体以更改FK参考或其他数据。您的代码信任返回的实体,只需将其附加并提交更改作为更新即可。无论您在用户界面中显示什么,我都可以更改对象图中的任何内容。
您可能面临的问题是EF尝试解析相关实体,并且由于它们不与该DBContext相关联,因此它将它们视为新记录。您可以在顶层使用AddOrUpdate,但我认为这不适用于相关实体。它不会自动与Attach配合使用,因此,如果它不能与AddOrUpdate配合使用,我也不会感到惊讶。如果您需要将实体图重新附加到上下文,那么潜入图并处理更新,插入和/或删除可能会很麻烦。您可以使用诸如GraphDiff(https://github.com/zzzprojects/GraphDiff)之类的库来协助完成此工作。