Entity framework EF6将具有两个外键的子记录添加到父表
我的问题涉及一个任务表,以及它们之间的关系 业务模型是,每个任务都有一个在开始之前需要完成的任务列表 我的C#EF6 winforms应用程序有以下两个表(简化) 我有一个主键为的任务表Entity framework EF6将具有两个外键的子记录添加到父表,entity-framework,entity-framework-6,Entity Framework,Entity Framework 6,我的问题涉及一个任务表,以及它们之间的关系 业务模型是,每个任务都有一个在开始之前需要完成的任务列表 我的C#EF6 winforms应用程序有以下两个表(简化) 我有一个主键为的任务表 [TaskID] [int] IDENTITY(1,1) NOT NULL 和只有两列的前置表 [TaskID] [int] NOT NULL, [PredecessorTaskId] [int] NOT NULL 其中主键由两列组成 TaskID和PredecessorTaskId都是任务表的外键 在de
[TaskID] [int] IDENTITY(1,1) NOT NULL
和只有两列的前置表
[TaskID] [int] NOT NULL,
[PredecessorTaskId] [int] NOT NULL
其中主键由两列组成
TaskID
和PredecessorTaskId
都是任务表的外键
在designer edmx中,我看不到前置表,而是有一行从任务表返回到它本身
通过运行自定义工具创建的代码是
public partial class task
{
public task()
{
this.NeedsTasks = new HashSet<task>();
this.NeededByTasks = new HashSet<task>();
}
public int TaskID { get; set; }
public virtual ICollection<task> NeedsTasks { get; set; }
public virtual ICollection<task> NeededByTasks { get; set; }
// other fields
}
我明白了
这不是我想要的,因为它是第一个应该具有空数据的前置任务,指示第一个任务不需要任何其他任务来启动
如果在循环中取消对SaveChanges调用的注释,则会得到正确的结果
但是,我更希望只调用一次SaveChanges,因此有一个事务
我还尝试添加
prevtask.NeededByTasks.Add(task);
打电话给
task.NeedsTasks.Add(prevtask);
但是,它没有什么区别它实际上是SQL结果中包含
NULL
数据的第一个前置元素(即workflowTasks
列表中的第一个元素)。如果稍微扩展SQL查询,您可以看到:
select k.taskid, p.taskid, p.predecessortaskId, k.taskoffsetid
from task k left outer join predecessor p on k.taskid = p.taskid
where etc
order by taskoffsetid
现在的结果是:
taskid taskid predecessortaskid taskoffsetid
568188 NULL NULL 1
568187 568187 568188 2
568189 568189 568187 3
568190 568190 568189 4
568191 568191 568190 5
但是,taskid
的生成顺序与您设置的taskoffsetid
以及任务在输入列表中的排序顺序不同
如果插入包含许多实体的复杂对象图,则不能假定生成键的任何特定顺序。EF发送到数据库的INSERT语句序列受EF控制。除非我通过多次调用SaveChanges
(正如您已经看到的)来明确地强制生成密钥,否则我不会以任何方式依赖于以我想要的特定顺序生成密钥的期望
通过使用(var scope=newtransactionscope()){…scope.Complete();}块将整个循环包装到一个中,可以解决在单个事务中运行多个SaveChanges
调用的问题
然而,问题是:您真的需要排序的任务ID
?如果根本不引用键,您实际上可以按照任务的依赖关系顺序运行任务,例如:
using (var db = new MyDbContext)
{
var task = db.Tasks.Where(t => !t.NeedsTasks.Any()).SingleOrDefault();
while (task != null)
{
// run task / do something with task...
task = task.NeededByTasks.SingleOrDefault(); // lazy loading
}
}
select k.taskid, p.taskid, p.predecessortaskId, k.taskoffsetid
from task k left outer join predecessor p on k.taskid = p.taskid
where etc
order by taskoffsetid
taskid taskid predecessortaskid taskoffsetid
568188 NULL NULL 1
568187 568187 568188 2
568189 568189 568187 3
568190 568190 568189 4
568191 568191 568190 5
using (var db = new MyDbContext)
{
var task = db.Tasks.Where(t => !t.NeedsTasks.Any()).SingleOrDefault();
while (task != null)
{
// run task / do something with task...
task = task.NeededByTasks.SingleOrDefault(); // lazy loading
}
}