具有额外配置的导航属性的模型派生类

Posted

技术标签:

【中文标题】具有额外配置的导航属性的模型派生类【英文标题】:Derived class from model with additionally configured navigational properties 【发布时间】:2021-11-03 17:37:15 【问题描述】:

注意:我的数据库已经用 sql 编写,EF 设置不会影响 SQL 对象的实际创建。

我正在尝试创建其他项目可以继承的“基础”上下文和模型,希望基础上下文和模型不需要修改,而是随着其他关系的建立而扩展。这是我目前的尝试

文件 1:

namespace BaseProject.Models 
   public class ClassA 
      public int Id  get;set; 
      public string Value  get; set; 
      
      public void DoConfiguring(ModelBuilder modelBuilder) 
            // do setup to define the key and table
      
   

文件 2:

namespace ProjectB.Models 
   public class ClassA: BaseProject.Models.ClassA 
      public ClassC NavPropertyToAnotherClass  get; set; 
      public void DoConfiguring(ModelBuilder modelBuilder) 
            // do setup for nav property here
      
   

在这种情况下,BaseProject 的所有模型都已配置,然后 ProjectB 的所有模型都已配置。我希望将所有数据都保存在 1 个表中,如 ClassA 配置中定义的那样。我没有添加任何其他列或信息。我只是希望能够像使用 ClassA 一样使用 ClassB,但需要设置额外的导航属性。

我遇到了鉴别器问题和其他一些正在停止的小问题。是我的设置错误,还是这种类型的问题目前无法通过继承和 EF Core 解决。

编辑: 最终目标是能够在建立新关系时向继承的模型添加导航属性,以便基本模型和实体几乎可以保持不变。

另一种尝试来解释我的设想。


//----------- File ---------------//
namespace BaseProject.Models 
    public class Person 
        public int Id  get;set; 
        public string FirstName  get; set; 
        public string LastName  get; set; 
        public int? ParentOneId  get; set; 
        public int? ParentTwoId  get; set; 
        
        public Person ParentOne  get; set; 
        public Person ParentTwo  get; set; 
        public ICollection<Person> ChildrenOne  get; set; 
        public ICollection<Person> ChildrenTwo  get; set; 
        
        public void OnModelCreating(ModelBuilder modelBuilder) 
            var builder = modelBuilder.Entity<Person>();
            builder.HasMany(l => l.ChildrenOne)
                .WithOne(co => co.ParentOne)
                .HasForeignKey(co => co.ParentOneId);
            
            builder.HasMany(l => l.ChildrenTwo)
                .WithOne(co => co.ParentTwo)
                .HasForeignKey(co => co.ParentTwoId);
                
            builder.ToTable("dbo", "Person");
            
            builder.HasKey(f => f.Id);
        
    

//--------------------------//

//----------- File ---------------//
namespace BaseProject.Contexts 
    public class BaseContext : DbContext 
        
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        
            new Person().OnModelCreating(modelBuilder);
            base.OnModelCreating(modelBuilder);
        
    

//--------------------------//

//----------- File ---------------//
namespace ExtraCurricularProject.Models 
    public class ExtraCurricular 
        public int Id  get; set; 
        public string Name  get; set; 
        // other stuff
        
        public ICollection<PersonExtraCurricular> PersonExtraCurriculars  get; set; 
        public void OnModelCreating(ModelBuilder modelBuilder) 
            var builder = modelBuilder.Entity<ExtraCurricular>();
                
            builder.ToTable("dbo", "ExtraCurricular");
            
            builder.HasKey(f => f.Id);
        
    

//----------------------------//


//----------- File ---------------//
namespace ExtraCurricularProject.Models 
    public class Person : BaseProject.Models.Person 
    
        public ICollection<PersonExtraCurricular> PersonExtraCurriculars  get; set; 
        
        public void OnModelCreating(ModelBuilder modelBuilder) 

        
    

//--------------------------//


//----------- File ---------------//
namespace ExtraCurricularProject.Models 
    public class PersonExtraCurricular 
        public int PersonId  get; set; 
        public int ExtraCurricularId  get; set; 
        
        public Person Person  get; set; 
        public ExtraCurricular ExtraCurricular  get; set; 
        
        public void OnModelCreating(ModelBuilder modelBuilder) 
            var builder = modelBuilder.Entity<PersonExtraCurricular>();
            builder.HasOne(pec => pec.Person)
                .WithMany(p => p.PersonExtraCurriculars)
                .HasForeignKey<PersonExtraCurricular>(pec => pec.PersonId);
            
            builder.HasOne(pec => pec.ExtraCurricular)
                .WithMany(ec => ec.PersonExtraCurriculars)
                .HasForeignKey<PersonExtraCurricular>(pec => pec.ExtraCurricularId);
                
            builder.ToTable("dbo", "PersonExtraCurricular");
            
            builder.HasKey(pec => new  pec.PersonId, pec.ExtraCurricularId );
        
    

//--------------------------//

//----------- File ---------------//
namespace ExtraCurricularProject.Contexts 
    public class ExtraCurricularContext : BaseContext 
        
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        
            new Person().OnModelCreating(modelBuilder);
            new ExtraCurricular().OnModelCreating(modelBuilder);
            new PersonExtraCurricular().OnModelCreating(modelBuilder);
            base.OnModelCreating(modelBuilder);
        
    

//--------------------------//

尝试使用这种类型的模式它说我需要一个鉴别器,但我不想让 BaseProject.Models.Person 和 ExtraCurricularProject.Models.Person 带回不同的数据,我只想要 ExtraCurricularProject.Models.Person能够访问那些其他导航属性。

【问题讨论】:

这些DoConfiguring 方法在哪里运行?目前尚不清楚这两个类是否都已配置。 (假设第二个ClassA实际上是ClassB)。 我添加了另一个尝试,看看它是否能更好地捕捉到我想象的映射方式 【参考方案1】:

注意:... EF 设置不会影响 SQL 对象的实际创建。

这是不正确的。将属性添加到派生类后,您需要使 EF 与数据库同步 - 换句话说,更新表和关系。一旦你这样做了,EF 会尝试将你的层次结构映射到表(假设你使用 EF Core 5),这就是为什么你会在 Discriminator 列(这是 EF 处理层次结构的方式)出现错误。

现在,只有在 DbContext 中有 ProjectB.ClassA 时才会发生这种情况。你?如果你不这样做,那么根本原因就不同了。请出示DbContext 代码。您暗示那里也有基类和派生类 - 这有点令人费解,可能是问题的真正原因。

另外,请显示您遇到的错误

【讨论】:

我在描述我的首选结果方面做得不好。基本上,我希望有一个项目,它有一个 DbContext ,其中包含一些表和其他项目的基本信息,以便能够从该基本信息继承并将导航属性添加到它们的特定表中。我不希望基本上下文和定义必须知道所有具有依赖外键的表。 DbContext(代表数据库)和许多DbSets(代表表)。你不需要继承DbContext。您可以DbSet 类派生,只要您不将派生类本身标记为DbSet - 它们就不会保留在数据库中。但看起来您想要保留派生类的信息 - “导航属性”映射到外键。 “我不希望基本上下文知道表......”这句话没有意义。也许从头开始,解释你真正想做的事情! 我正在尝试 Felix D:

以上是关于具有额外配置的导航属性的模型派生类的主要内容,如果未能解决你的问题,请参考以下文章

从android中的派生类更新父类(包括导航视图)中声明的imageview

将基类转换为派生类[重复]

具有共同属性但值不同的派生类的正确设计设置

C#编程,关于基类和派生类

c ++设计:从基类转换为派生类,没有额外的数据成员

使用具有指向派生类对象的指针的基类指针数组调用派生类方法