This is a migrated thread and some comments may be shown as answers.

Two Layer Vertical Inheritance - Discriminator values

5 Answers 69 Views
Data Access Free Edition
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Gary
Top achievements
Rank 1
Gary asked on 01 Oct 2015, 04:54 PM

I'm trying to not go into too much detail but provide enough. If it helps I have a test project I can send you ... 

In short what I am trying to do is create a 2 layer vertical inheritance. 

Layer One

I have defined a PRODUCT model/table mapping with a discriminator column

 

var configuration = new  MappingConfiguration<ProductEntity>();
    configuration.HasProperty(x => x.ProductType)
        .HasFieldName("_productType")
        .WithDataAccessKind(DataAccessKind.ReadWrite)
        .ToColumn("DeliverableType")
        .IsNotNullable()
        .HasColumnType("nvarchar")
        .WithVariableLength(50);
    //
    // Identify the discriminator property
    configuration.HasDiscriminator().ToColumn("ProductType");

 
"Deliverable" and "Package" model/tables are derived from this PRODUCT and mapped to define the value to be inserted into the discriminator field of the parent.

 

var configuration = new  MappingConfiguration<ProductDeliverableEntity>();
    //
    // Identify the product type discriminator
    configuration.HasDiscriminatorValue("SINGLE");
     
var configuration = new  MappingConfiguration<ProductDeliverablePackageEntity>();
    //
    // Identify the product type discriminator
    configuration.HasDiscriminatorValue("PKG");

 

"Deliverable" is further extended by a specific ​TYPE of deliverable. In our example we have a PRINT deliverable and a VIDEO ​deliverable which derive from the ProductDeliverableEntity above.

 

var configuration new MappingConfiguration<PrintProductDeliverableEntity> ();
    //
    // Identify the value to assign to the DeliverableType Discriminator column
    configuration.HasDiscriminatorValue("PRINT");
     
var configuration new MappingConfiguration<VideoProductDeliverableEntity> ();
    //
    // Identify the value to assign to the Discriminator column
    configuration.HasDiscriminatorValue("VIDEO");

 
In order to support th​is second tier of inheritance, I added the definition of it's own discriminator column to the ProductDeliverableEntity definition so that it could support the specific types of being derived. 

 

var configuration = new  MappingConfiguration<ProductDeliverableEntity>();
    //
    // Identify the value to assign to the ProductType Discriminator column
    configuration.HasDiscriminatorValue("SINGLE");
 
    //
    // Identify the column which defines which TYPE this is (i.e. discriminator)
    configuration.HasDiscriminator().ToColumn("DeliverableType");

 

 When I attempt to add either of the specific Deliverable types (Video or Print) I am getting a Cannot insert a NULL value into the "DeliverableType" field. 

 

//
// Assemble
DbContext ctx = new DbContext();
VideoProductDeliverableEntity video = new VideoProductDeliverableEntity();
PrintProductDeliverableEntity print = new PrintProductDeliverableEntity();
ProductDeliverablePackageEntity pkg = new ProductDeliverablePackageEntity();
 
 
video.ProductName   = "120 second greeting";
video.ProductSku    = "VDO-120-MPG";
video.VideoFormat   = "mpg";
//video.DeliverableType = "TESTCODE";
 
print.ProductName   = "Fringe Badge";
print.ProductSku    = "BDG-FRINGE-40";
print.Media         = "Badge";
print.Printer = "DS40";
//print.DeliverableType = "TESTCODE";
 
pkg.Contents.Add(video);
pkg.Contents.Add(print);
pkg.ProductName = "Video print";
pkg.ProductSku = "VDOPRNT-001";
 
 
ctx.Add(video);
ctx.Add(print);
ctx.Add(pkg);
 
ctx.SaveChanges();

 

When I uncomment the lines where the DeliverableType is explicitly assigned, the test code completes running. What I have discovered however, is that the "VIDEO" and "PRINT" discriminator values are being inserted into the ProductType discriminator field instead of the DeliverableType, thus resulting in a NULL value being assigned to the DeliverableType (which is not allowed).

The discriminator value of "SINGLE" is never used at all. I am not sure if there is an issue that causes the discriminator to be passed all the way to the lowest level instead of the "next" or first level that defines a discriminator. This is a fundamental piece of our architecture decision-making so any help would be greatly appreciated.

I created a small test project that illustrates the issue if providing that would help I would be happy to forward that along. 

 

 

 

5 Answers, 1 is accepted

Sort by
0
Accepted
Thomas
Telerik team
answered on 06 Oct 2015, 09:12 AM
Hi Gary,

reading through your description I understood:
(a) You have a class hierarchy ProductEntity <- ProductDeliverableEntity <- PrintProductDeliverableEntity.
(b) You defined two different discriminator columns.

When a PrintProductDeliverableEntity is a ProductEntity, the discrimination needs to happen for the values in the ProductEntity table. There must not be two different discriminator columns in this one table hierarchy. DataAccess does not support such setups (the discriminator values could be contradictory), and the single discrimination value will be stored in the root table. DataAccess will know from your CLR class model which class extends which other class and infers the needed table relationship from CLR inheritance hierarchy. If you assign another table to hold that values for a particular class, the table will be used only for instances of this class.
So I think the issue is with the second discriminator column that was defined, and I think removing it would resolve this issue.
If it does not, or if I did not understand your setup correctly, please contact us again with the repro that you mentioned.

Regards,
Thomas
Telerik
 
Check out the latest announcement about Telerik Data Access vNext as a powerful framework able to solve core development problems.
0
Gary
Top achievements
Rank 1
answered on 06 Oct 2015, 06:32 PM

Thank you for your response and I think I understand your explanation. The ​scenario I am facing is that I need to be able to represent both a PackageEntity and a ProductDeliverableEntity as individual ProductEntities. If that was all there was to it, I would create a discriminator on the ProductEntity to distinguish whether the product was of a Package or Deliverable type .. no sweat. The problem comes up that the ProductDeliverableEntity could be of either Video or Print type. At the ProductEntity level we do not care whether the Product is a video or a print, just ​whether it is a Deliverable or a Package. But since I have already applied "discrimination" logic at the Deliverable level I am unable to apply it at the product level ... I have attached an image to illustrate what I am trying to do. It sounds like I will need to be a little more creative in how I resolve this issue.  <Diagram>

Thank you!

0
Thomas
Telerik team
answered on 07 Oct 2015, 03:57 PM
Hi Gary,

I think I would not think in this hierarchy. IsA-kind relationships are represented with classes, but maybe a packaging is a property? Would that solve the issue? Again, we are not supporting more than one discriminator value per table hierarchy, thus class hierarchy.

Regards,
Thomas
Telerik
 
Check out the latest announcement about Telerik Data Access vNext as a powerful framework able to solve core development problems.
0
Gary
Top achievements
Rank 1
answered on 08 Oct 2015, 01:09 PM

Thank you for your feedback. I am certainly open to any options, technical or architectural that would address my issue. I think, however that the "is-A" description is still appropriate here as an individual Deliverable "is a" product and a Package of Deliverables' also "is a" product. Having a many-to-many relationship makes using a property a little difficult. I think that the solution I have come upon, for now anyway, is to apply an "IProduct" interface to each type's class definition. I had to add a field to the Deliverable database table to support it but that's ok. This allows me to create a Data Transfer Object that represents ​the simple product interface regardless of whether they are a ​Package or Deliverable. 

Since creating​, updating or deleting a product would not occur at this high of an abstracted level I don't really NEED the ORM to manage that relationship. 

I think that that will work ... Thanks again!!

 

 

0
Thomas
Telerik team
answered on 13 Oct 2015, 06:54 AM
Hi Gary,

using an interface is a good solution to this problem I think. 

Regards,
Thomas
Telerik
 
Check out the latest announcement about Telerik Data Access vNext as a powerful framework able to solve core development problems.
Tags
Data Access Free Edition
Asked by
Gary
Top achievements
Rank 1
Answers by
Thomas
Telerik team
Gary
Top achievements
Rank 1
Share this question
or