【发布时间】:2018-10-04 13:35:20
【问题描述】:
我已经阅读了几篇关于这个(例如Why can't EF handle two properties with same foreign key, but separate references/instances?)问题的帖子,但没有一个提供令人满意的解决方案。
使用 EF6,插入具有两个导航属性的对象失败,当属性具有相同类型时,表示相同的条目(即具有相同的主键值)但是是两个不同的对象实例。
设置:
public abstract class EntityBase
{
public int Id { get; set; }
public bool IsTransient => Id <= 0;
}
public class Person : EntityBase
{
public string Name { get; set; }
}
public class Task : EntityBase
{
public int CreatorId { get; set; }
public int ReceiverId { get; set; }
public string Text { get; set; }
public Person Creator { get; set; }
public Person Receiver { get; set; }
}
当我尝试插入如下所示的新任务时,当creator 和receiver 相同Person(即具有相同的Id 值)时会发生异常。例外情况是:“...因为 'Person' 类型的多个实体具有相同的主键值。”。
public void AddTask(string text, Person creator, Person receiver)
{
using (var context = new MyEntities())
{
Task task = new Task()
{
Text = text,
Creator = creator,
Receiver = receiver
};
context.Task.Add(task);
context.Entry(creator).State = EntityState.Unchanged;
context.Entry(receiver).State = EntityState.Unchanged; // Exception is raised here
context.SaveChanges();
}
}
使用以下代码可以避免该异常:
public void AddTask(string text, Person creator, Person receiver)
{
using (var context = new MyEntities())
{
Task task = new Task()
{
Text = text,
Creator = creator,
Receiver = receiver
};
context.Task.Add(task);
context.Entry(creator).State = EntityState.Unchanged;
if (creator.Id == receiver.Id)
task.Receiver = creator;
else
context.Entry(receiver).State = EntityState.Unchanged;
context.SaveChanges();
}
}
问题:除了在插入之前检查导航属性的 Id 值之外,有什么方便的方法可以避免异常吗?
这是一个简单的例子。要插入更复杂的对象图,像此处所示的手动检查非常麻烦。
编辑:异常消息是(德语):
System.InvalidOperationException: Fehler beim Speichern oder Übernehmen der Änderungen, weil mehrere Entitäten des Typs '人' den gleichen Primärschlüsselwert aufweisen。 Stellen Sie sicher, dass explizit festgelegte Primärschlüsselwerte 伊恩德蒂格信德Die von der Datenbank generierten Primärschlüssel müssen in der Datenbank und im Entity Framework-Modell ordnungsgemäß 配置存在。 Verwenden Sie den Entity Designer für die Database 第一/模型第一配置。 Verwenden Sie die Fluent-API 'HasDatabaseGeneratedOption' oder 'DatabaseGeneratedAttribute' für die 代码优先配置。
我明确设置EntityState 的原因是因为我正在处理分离的对象。如果我不设置Person 对象的状态,它将作为新条目插入。为了避免这种情况,我将其标记为Unchanged。
【问题讨论】:
-
我已经多次遇到这样的设置,但从未遇到过这个特殊问题。你能发布完整的例外吗?
-
您能解释一下为什么使用
context.Entry(creator).State = EntityState.Unchanged;来标记状态吗?如果实体被跟踪,则没有必要。 -
@Stefan 请查看我的编辑。
-
哈,是的,这让我感到惊讶;似乎标记为
unchanged仍然会导致插入数据库。无论如何;我认为您正在努力推动 ORM,请记住它是一个完整的存储库。保持长期的 Db 上下文等可能会导致一些烦人的可维护性问题。我知道在这种情况下这对你没有多大帮助,但我建议让你的 ORM(实体框架)调用“简短”和隔离。有关域模型的示例(可能会对您有所帮助),请参阅:stackoverflow.com/questions/23648832/… -
感谢您的详细说明,但实际上我认为像我这样使用分离的对象会导致不保持 长期存在的 Db 上下文 并且还保持 ORM 调用简短...
标签: c# entity-framework entity-framework-6