最后一个实体的实体框架循环依赖

时间:2016-10-16 17:20:33

标签: entity-framework entity-framework-core

请考虑以下实体

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?

1 个答案:

答案 0 :(得分:11)

这就是我喜欢称之为青睐的孩子问题:父母有多个孩子,但其中一个是特别的。这会导致现实生活中的问题......以及数据处理中的问题。

在您的班级模型中,What(顺便说一下,这是一个合理的名称?)作为孩子有Tracks,但其中一个,LastTrackWhat的特殊孩子{ {1}}保留参考。

如果在一个事务中创建了WhatTrack,则EF会尝试使用生成的What.Id插入TrackWhatId }。但在保存What之前,它需要生成最后一个Track的ID。由于SQL数据库无法同时插入记录,因此无法在一个独立的事务中建立此循环引用。

您需要一个交易来保存What及其Track以及后续交易以设置What.LastTrackId

要在一个数据库转换中执行此操作,您可以将代码包装在TransactionScope

using(var ts = new TransactionScope())
{
    // do the stuff
    ts.Complete();
}

如果发生异常,ts.Complete();将不会发生,并且在TransactionScope被处置时将发生回滚。