代码之家  ›  专栏  ›  技术社区  ›  G_P

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

  •  0
  • G_P  · 技术社区  · 7 年前

    我有两个代码优先实体,package和packageentry,在ef core中设置时遇到问题。

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

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

    这两个实体:

        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();
    
          }
    

    public class PackageEntry
    {
        public int DisplayOrder { get; set; }
        public int PackageID { get; set; }
        public Package Package { get; set; }
        public int Quantity { get; set; }
        public Package ParentPackage { get; set; }
        public int ParentPackageID { get; set; }
    }
    

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

    modelBuilder.Entity<Package>().HasMany(x => x.PackageEntries).WithOne();
    modelBuilder.Entity<PackageEntry>().HasOne(x => x.Package).WithOne().HasForeignKey(typeof(PackageEntry), "PackageID");
    

    它不会引发错误,但我看到的是,当将PackageEntry添加到包时,在对上下文调用SaveChanges时,它不会被保存。

    我是在用Fluent API做什么错事还是在做其他事情?

    编辑 我错过了将顶级包添加到上下文中,一旦完成,将添加到其中的包条目将被保存。对于流畅的API设置和任何最佳实践,我仍将不胜感激。

    从PackageEntry实体,我需要知道父包和包含的包,它们将是对同一类型的单独引用。 我似乎不能用fluent API设置这个,当通过ef加载父包时,它不包含任何PackageEntry对象,即使它们的ParentPackageID设置正确。

    2 回复  |  直到 7 年前
        1
  •  1
  •   G_P    7 年前

    根据EF专家的一些离线建议,我通过删除packageentry.package的导航属性并简单地手动处理该package实体的外键来解决这个问题。

    一旦我这样做了,现在当父包实体被加载时,它就会正确地加载子包中心。

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

    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);
    
        2
  •  0
  •   krillgar    7 年前

    您的 Package.PackageEntries 集合已标记 [NotMapped] 它没有setter。不管怎样,EntityFramework都不会接受。

    我从未尝试过使用 IReadonlyCollection<T> 有了EntityFramework,但我想英孚也不会喜欢它。

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

    public virtual IReadOnlyCollection<PackageEntry> PackageEntries {
        get {
            return _packageEntries.ToList().AsReadonly();
        }
        protected internal set {
            _packageEntries = value;
        }
    }
    

    当然,这需要您删除 readonly 来自私有成员变量。

    也就是说,我不确定ef是否有一个内部列表,它最终会分配给属性,但我想它会调用 Add() 集合上的方法(这就是属性必须 ICollection<T> 而不是 IEnumerable<T> .

    因此,如果这一切仍然不起作用,你应该 _packageEntries protected internal 并将其作为您的EF集合。那么你只能公开你的 PackageEntries 就像你现在做的。

    推荐文章