请考虑以下实体
public class What {
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Track> Tracks { get; set; }
public int? LastTrackId { get; set; }]
public Track LastTrack { get; set; }
}
public class Track {
public Track(string what, DateTime dt, TrackThatGeoposition pos) {
What = new What { Name = what, LastTrack = this };
}
public int Id { get; set; }
public int WhatId { get; set; }
public What What { get; set; }
}
我使用以下命令配置实体:
builder.HasKey(x => x.Id);
builder.HasMany(x => x.Tracks).
WithOne(y => y.What).HasForeignKey(y => y.WhatId);
builder.Property(x => x.Name).HasMaxLength(100);
builder.HasOne(x => x.LastTrack).
WithMany().HasForeignKey(x => x.LastTrackId);
您是否可以看到有一个想要的循环引用:
What.LastTrack <-> Track.What
当我尝试向上下文添加Track
时(实际上在SaveChanges
上):
Track t = new Track("truc", Datetime.Now, pos);
ctx.Tracks.Add(t);
ctx.SaveChanges();
我收到以下错误:
无法保存更改,因为在要保存的数据中检测到循环依赖关系:&#39;&#39;什么&#39; {&#39; LastTrackId&#39;} - &gt; &#39;轨道&#39; {&#39; Id&#39;},&#39;追踪&#39; {&#39; WhatId&#39;} - &gt; &#39;什么&#39; {&#39;标识&#39;}&#39;
我想说......是的,我知道但是......
这样的配置是否适用于EF Core?
答案 0 :(得分:11)
这就是我喜欢称之为青睐的孩子问题:父母有多个孩子,但其中一个是特别的。这会导致现实生活中的问题......以及数据处理中的问题。
在您的班级模型中,What
(顺便说一下,这是一个合理的名称?)作为孩子有Tracks
,但其中一个,LastTrack
是What
的特殊孩子{ {1}}保留参考。
如果在一个事务中创建了What
和Track
,则EF会尝试使用生成的What.Id
插入Track
个WhatId
}。但在保存What
之前,它需要生成最后一个Track
的ID。由于SQL数据库无法同时插入记录,因此无法在一个独立的事务中建立此循环引用。
您需要一个交易来保存What
及其Track
以及后续交易以设置What.LastTrackId
。
要在一个数据库转换中执行此操作,您可以将代码包装在TransactionScope
:
using(var ts = new TransactionScope())
{
// do the stuff
ts.Complete();
}
如果发生异常,ts.Complete();
将不会发生,并且在TransactionScope
被处置时将发生回滚。