简体   繁体   English

当两个表都是 TPH 并且关系在基类中时,如何声明父子关系?

[英]How to declare a parent child relationship when both tables are TPH and the relationship is in the base classes?

My problem relates to sales orders and sales invoices but I find it easier to think of pets and their offspring... without creating a full pedigree model.我的问题与销售订单和销售发票有关,但我发现更容易想到宠物及其后代......而无需创建完整的谱系 model。

My DbContext我的数据库环境

using System;
using DevExpress.ExpressApp.EFCore.Updating;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using DevExpress.Persistent.BaseImpl.EF.PermissionPolicy;
using DevExpress.Persistent.BaseImpl.EF;
using DevExpress.ExpressApp.Design;
using DevExpress.ExpressApp.EFCore.DesignTime;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using DevExpress.ExpressApp.DC;
using System.Collections.Generic;
    

namespace Pets.Module.BusinessObjects
{
    [TypesInfoInitializer(typeof(PetsContextInitializer))]
    public class PetsEFCoreDbContext : DbContext
    {
        public PetsEFCoreDbContext(DbContextOptions<PetsEFCoreDbContext> options) : base(options)
        {
        }

        public DbSet<Cat> Cats { get; set; }
        public DbSet<Dog> Dogs { get; set; }
        public DbSet<Kitten> Kittens { get; set; }
        public DbSet<Puppy> Puppys { get; set; }

      
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Pet>()
              .HasDiscriminator(x=> x.IsCat)
              .HasValue<Cat>(true)
              .HasValue<Dog>(false);

            modelBuilder.Entity<BabyPet>()
              .HasDiscriminator(x => x.IsCat)
              .HasValue<Kitten>(true)
              .HasValue<Puppy>(false);

            modelBuilder.Entity<Puppy>().HasOne(x => x.Parent).WithMany(x => x.Puppies);
            modelBuilder.Entity<Kitten>().HasOne(x => x.Parent).WithMany(x => x.Kittens);
        }
    }
}

My classes我的课程

public abstract class Pet
{
    [Key] public int Id { get; set; }
    public string Name { get; set; }
    public bool? IsCat { get; set; }
}

public abstract class BabyPet
{


    [Key] public int Id { get; set; }

    public int ParentPetId { get; set; }

    [ForeignKey("ParentPetId")]
    public virtual Pet Parent { get; set; }
    public string Name { get; set; }
    public bool? IsCat { get; set; }

}
public class Kitten : BabyPet
{
     new public virtual Cat Parent  { get; set; }
}

public class Dog : Pet
{
    public Dog()
    {
        Puppies = new List<Puppy>();
    }
    [Aggregated]
    public virtual List<Puppy> Puppies { get; set; }
}

public class Cat : Pet
{
    public Cat()
    {
        Kittens = new List<Kitten>();
    }
    [Aggregated]
    public virtual List<Kitten> Kittens { get; set; }
}

public class Puppy : BabyPet
{
    new public virtual Dog Parent { get; set; }
}

Also there is还有

public class PetsContextInitializer : DbContextTypesInfoInitializerBase
{
    protected override DbContext CreateDbContext()
    {
        var optionsBuilder = new DbContextOptionsBuilder<PetsEFCoreDbContext>()
            .UseSqlServer(@";");
        return new PetsEFCoreDbContext(optionsBuilder.Options);
    }
}

However this creates the following structure in BabyPet但是,这会在 BabyPet 中创建以下结构

婴儿宠物结构

Where as I just want我想要的地方

我想要的是

[Update] I was able to get the structure I want by specifying the foreignkey in OnModelCreating [更新] 通过在 OnModelCreating 中指定外键,我能够获得我想要的结构

modelBuilder.Entity<Puppy>().HasOne(x => x.Parent).WithMany(x => x.Puppies).HasForeignKey(x=>x.ParentPetId);
modelBuilder.Entity<Kitten>().HasOne(x => x.Parent).WithMany(x => x.Kittens).HasForeignKey(x => x.ParentPetId);  
 

However when I try to add a Kitten to a cat via the XAF Winforms UI I get:但是,当我尝试通过 XAF Winforms UI 将小猫添加到猫时,我得到:

Unable to cast object of type 'SimplePets.Module.BusinessObjects.Kitten' to type 'SimplePets.Module.BusinessObjects.Puppy'.

   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.get_Item(IPropertyBase propertyBase)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.GetCurrentValue(IPropertyBase propertyBase)
   at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.TryAddPropertyNameToCollection(InternalEntityEntry entity, ICollection`1 propertiesToCheck, IPropertyBase property)
   at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.TryAddPropertyNameToCollection(InternalEntityEntry entity, IProperty property, ICollection`1 propertiesToCheck)
   at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.GetPropertiesToCheck(InternalEntityEntry entity)
   at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.CheckReadWritePermissionsForNonIntermediateObject(InternalEntityEntry entity)
   at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.CheckReadWritePermissions(InternalEntityEntry entity)
   at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.CheckIsGrantedToSave(InternalEntityEntry entity)
   at DevExpress.EntityFrameworkCore.Security.NetStandard.ChangeTracking.SecurityStateManager.GetEntriesToSave(Boolean cascadeChanges)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(DbContext _, Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
   at DevExpress.ExpressApp.EFCore.EFCoreObjectSpace.DoCommit()
   at DevExpress.ExpressApp.BaseObjectSpace.CommitChanges()
   at DevExpress.ExpressApp.Win.SystemModule.WinModificationsController.Save(SimpleActionExecuteEventArgs args)
   at DevExpress.ExpressApp.SystemModule.ModificationsController.saveAction_OnExecute(Object sender, SimpleActionExecuteEventArgs e)
   at DevExpress.ExpressApp.Actions.SimpleAction.RaiseExecute(ActionBaseEventArgs eventArgs)
   at DevExpress.ExpressApp.Actions.ActionBase.ExecuteCore(Delegate handler, ActionBaseEventArgs eventArgs)

I put my example on GitHub here我把我的例子放在GitHub

Docs link about relationships here and tph inheritance is here关于关系的文档链接在这里,tph inheritance 在 这里

I think I must have the data structures correct after my update to onModelCreating.我想我必须在更新到 onModelCreating 后让数据结构正确。 That is:那是:

modelBuilder.Entity<Puppy>().HasOne(x => x.Parent).WithMany(x => x.Puppies).HasForeignKey(x=>x.ParentPetId);
modelBuilder.Entity<Kitten>().HasOne(x => x.Parent).WithMany(x => x.Kittens).HasForeignKey(x => x.ParentPetId); 

I was able to work around the Cast Object error by using DBContext instead of ObjectSpace我能够通过使用 DBContext 而不是 ObjectSpace 来解决 Cast Object 错误

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using SimplePets.Module.BusinessObjects;
using System.Linq;

namespace SimplePets.Module.Win.Controllers
{
    public class KittenViewController : ViewController
    {
        SimpleAction actionAddKittenEF;
        SimpleAction actAddKittenXAF;

        public KittenViewController() : base()
        {
            TargetObjectType = typeof(Kitten);
            TargetViewNesting = Nesting.Nested;

            actAddKittenXAF = new SimpleAction(this, "Add via OS", "View");
            actAddKittenXAF.Execute += actAddKittenXAF_Execute;

            actionAddKittenEF = new SimpleAction(this, "Add via Db", "View");
            actionAddKittenEF.Execute += actionAddKittenEF_Execute;
        }

        private void actionAddKittenEF_Execute(object sender, SimpleActionExecuteEventArgs e)
        {
            var cat = View.ObjectSpace.GetObject(((NestedFrame)Frame).ViewItem.CurrentObject) as Cat;
            var db = Helpers.MakeDb();
            var kitten = new Kitten
            {
                Parent = db.Cats.FirstOrDefault(c => c.Id == cat.Id),
                Name = $"baby {cat.Kittens.Count + 1} of {cat.Name}"
            };
            db.Kittens.Add(kitten);
            db.SaveChanges();
            View.ObjectSpace.Refresh();
        }

        //Errors
        private void actAddKittenXAF_Execute(object sender, SimpleActionExecuteEventArgs e)
        {
            var cat = View.ObjectSpace.GetObject(((NestedFrame)Frame).ViewItem.CurrentObject) as Cat;
            var os = View.ObjectSpace;
            var kitten = os.CreateObject<Kitten>();
            kitten.Parent = cat;
            kitten.Name = $"baby {cat.Kittens.Count + 1} of {cat.Name}";
            View.ObjectSpace.CommitChanges();
            View.ObjectSpace.Refresh();
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在父 class 或子类上使用 inheritance 时与另一个实体的关系 - Relationship with another Entity when using inheritance on parent class or on child classes 子关系在父 object 中不可用 - child relationship not available in parent object 如何在一对多关系中获取父项的子条目的参考? - How to get reference for child entries of the parent in one-to-many relationship? EF Core,一对多关系 - 如何使用单个视图在两个表中插入记录? - EF Core, one-to-many relationship - how to insert records in both tables with a single view? 一对一关系不会同时包含两个类 - One-to-one relationship does not carry both classes 如何使用实体框架检索父子关系数据并对其进行分页/过滤/排序 - How to retrieve parent child relationship data using entity framework and do pagination/filtering/sorting on it Entity Framework Core - 插入单向父子关系 - Entity Framework Core - Inserting One-Directional Parent Child Relationship 父实体上的软删除,但子/关系 EF Core 上的硬删除 - Soft delete on Parent Entity but Hard delete on Child/Relationship EF Core 如何为具有关系的多个表创建迁移。 - how to create Migration for multiple Tables with relationship. 如何在 Entity Framework Core 2.2 中使用预先加载策略实现自递归父子关系数据加载? - How to implement self-recursive parent-child relationship data loading with eager loading policy in Entity Framework Core 2.2?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM