Ef code first 是否可以通过Fluent API建立这种关系?

Ef code first 是否可以通过Fluent API建立这种关系?,ef-code-first,entity-framework-core,ef-fluent-api,Ef Code First,Entity Framework Core,Ef Fluent Api,我有两个代码优先实体,Package和PackageEntry,我在EF Core中设置时遇到了问题 我试图通过代码优先实体和Fluent API实现以下目标: 一个包可以包含任意数量的PackageEntry 每个PackageEntry都有一个对单个包实体的引用(包的不同实例,与包含PackageEntry集合的父包引用无关) 这两个实体: public class Package{ public Package() { _packa

我有两个代码优先实体,Package和PackageEntry,我在EF Core中设置时遇到了问题

我试图通过代码优先实体和Fluent API实现以下目标:

  • 一个包可以包含任意数量的PackageEntry
  • 每个PackageEntry都有一个对单个包实体的引用(包的不同实例,与包含PackageEntry集合的父包引用无关)
这两个实体:

    public class Package{   
      public Package()
      {
        _packageEntries = new List<PackageEntry>();
      }
      //trimmed other properties

      private readonly List<PackageEntry> _packageEntries;

      [NotMapped]
      public IReadOnlyCollection<PackageEntry> PackageEntries => _packageEntries.ToList().AsReadOnly();

      }
我目前使用的Fluent API不起作用:

modelBuilder.Entity<Package>().HasMany(x => x.PackageEntries).WithOne();
modelBuilder.Entity<PackageEntry>().HasOne(x => x.Package).WithOne().HasForeignKey(typeof(PackageEntry), "PackageID");
modelBuilder.Entity();
modelBuilder.Entity().HasOne(x=>x.Package).WithOne().HasForeignKey(typeof(PackageEntry),“PackageID”);
它没有抛出错误,但我看到的是,当一个PackageEntry被添加到一个包中时,在上下文上调用SaveChanges时,它不会被保存

我是不是在用fluentapi做什么错事

编辑 我没有将顶级包添加到上下文中,一旦添加完成,将保存添加到上下文中的包条目。我仍然希望对Fluent API设置和任何最佳实践发表意见


从PackageEntry实体中,我需要知道父包和包含的包,它们将是对同一类型的单独引用。我似乎无法使用Fluent API进行设置,当父包通过EF加载时,它不包含任何PackageEntry对象,即使其ParentPackageID设置正确。

您的
软件包。PackageEntries
集合被标记为
[NotMapped]
,并且它没有设置器。不管怎样,EntityFramework都不会接受这一点

我从未尝试过将
IReadonlyCollection
与EntityFramework一起使用,但我想EF也不会喜欢这样

您的第一次尝试应该是删除属性并按如下方式排列属性:

public virtual IReadOnlyCollection<PackageEntry> PackageEntries {
    get {
        return _packageEntries.ToList().AsReadonly();
    }
    protected internal set {
        _packageEntries = value;
    }
}
public class PackageEntry
{
    public int DisplayOrder { get; set; }
    public int PackageID { get; set; }
    //public Package Package { get; set; } //Handle manually
    public int Quantity { get; set; }
    public Package ParentPackage { get; set; }
    public int ParentPackageID { get; set; }
}
公共虚拟IReadOnlyCollection包入口{
得到{
返回_packageEntries.ToList().AsReadonly();
}
受保护内部集{
_包装商=价值;
}
}
当然,这将要求您从私有成员变量中删除
readonly

也就是说,我不确定EF是否有一个最终分配给属性的内部列表,但我可以想象它只会调用集合上的
Add()
方法(这就是为什么属性必须是
ICollection
而不是
IEnumerable


因此,如果这一切仍然不起作用,你应该制作
\u packageEntries
受保护的内部
并将其用作你的EF集合。然后你只能像现在这样公开你的
packageEntries

根据EF专家的一些离线建议,我通过删除PackageEntry.Package的导航属性,只需手动处理该包实体的外键

我曾经这样做过,现在当加载父包实体时,它会正确地加载子包入口

因此,PackageEntry类现在看起来如下所示:

public virtual IReadOnlyCollection<PackageEntry> PackageEntries {
    get {
        return _packageEntries.ToList().AsReadonly();
    }
    protected internal set {
        _packageEntries = value;
    }
}
public class PackageEntry
{
    public int DisplayOrder { get; set; }
    public int PackageID { get; set; }
    //public Package Package { get; set; } //Handle manually
    public int Quantity { get; set; }
    public Package ParentPackage { get; set; }
    public int ParentPackageID { get; set; }
}
以及Fluent API代码:

navigation = builder.Metadata.FindNavigation(nameof(Package.PackageEntries));
//EF access the PackageEntries collection property through its backing field
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);

modelBuilder.Entity<Package>().HasMany(x => x.PackageEntries)
            .WithOne("ParentPackage")
            .HasForeignKey(nameof(PackageEntry.ParentPackageID))
            .IsRequired()
            .OnDelete(DeleteBehavior.Restrict);
navigation=builder.Metadata.FindNavigation(name of(Package.PackageEntries));
//EF通过其备份字段访问PackageEntries集合属性
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
modelBuilder.Entity().HasMany(x=>x.PackageEntries)
.WithOne(“家长套餐”)
.HasForeignKey(名称(PackageEntry.ParentPackageID))
.IsRequired()
.OnDelete(DeleteBehavior.Restrict);

首先谢谢!-我基于此设计的一部分,实体正在按原样保存,我发现我没有将顶级包添加到上下文中,一旦我这样做了,包条目就会被保存。我仍然不是100%地认为我已正确映射了内容…这是一种非常有趣的方式。看起来您是sti我将错过EF设置中的
导航
,告诉它支持字段。这在我了解EF时不可用,非常有趣!如果你愿意,我可以更新我的答案,但我认为你对从这里开始的方向有更多的线索。你能添加你如何重新配置所有内容的代码吗?这将更有帮助ul适用于以后可能发现此问题的所有其他人。