Free inheritance and mapping API EF

I have a system with several self-regulatory objects with a one-to-many relationship (parent-child). I would like to use a common base class for all of these objects:

public class SelfReferencing { public SelfReferencing Parent {get; set;} public ICollection<SelfReferencing> Children {get; set;} } 

and inherits a specific object from SelfReferencing. Free API mapping requires the reference properties to be of the defining type when trying to do the following:

 modelBuilder.Entity<ConcreteSelfReferencing>() .HasMany(e => e.Children) .WithOptional(e => e.Parent); 

So, can you help me find an opportunity to use inheritance and get mapped objects?

THX

+6
source share
1 answer

Note. The example below is known as Table-Per-Hierarchy (TPH) - that is, all contained in a single table. Click this link for Table-Per-Type (TPT) , which has different tables for each type.

When using base types and inherited types, you must tell EF how to define an association for a specific inherited type.

Taking your code:

 public abstract class SelfReferencing { public SelfReferencing Parent { get; set; } public ICollection<SelfReferencing> Children { get; set; } } public class ConcreteSelfReferencing : SelfReferencing { } 

Now EF must decide whether the subclass is a ConcreteSelfReferencing class or any other type of subclass. This is determined by the discriminator of the table itself, to which the column is not part of your mapping.

To take another example, similar to the one I used in the past:

 public abstract class Policy { public int Id { get; set; } public string PolicyNumber { get; set; } } public class InsurancePolicy : Policy { } public class CarPolicy : Policy { } 

The table was structured as follows:

 | Id | PolicyNumber | Type | ..... | 1 CAR0001 C 2 ISN0001 I 

To get the EF, to bring them correctly, you would get:

 public class MyContext : DbContext { public MyContext() : base() { } public DbSet<Policy> Policies { get; set; } protected override void OnModelCreating(ModelBuilder builder) { var policyMap = modelBuilder.Entity<Policy>(); // Set up discriminators policyMap.Map<InsurancePolicy>(p => o.Requires("Type").HasValue("I")) .Map<CarPolicy>(p => o.Requires("Type").HasValue("C")); // Notice that `Type` is only used for the discriminators, not an actual // mapped property policyMap.HasKey(x=>x.Id); policyMap.Property(x=>x.PolicyNumber); } } 

And from your code, you can do the filtering yourself or put the filtering in the DbContext . Here is an example from a separate class.

 public class PolicyRepository { private MyContext context = new MyContext(); public PolicyRepository() { } public IQueryable<InsurancePolicy> GetInsurancePolicies() { return this.context.Policies.OfType<InsurancePolicy>(); } public IQueryable<CarPolicy> GetCarPolicies() { return this.context.Policies.OfType<CarPolicy>(); } } 
+4
source

Source: https://habr.com/ru/post/970191/


All Articles