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

Vertical Inheritance and the discriminator column - Using Code only

5 Answers 183 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 14 Sep 2015, 05:15 PM

Vertical Inheritance and the discriminator column - Using Code only

I am trying to map a vertical inheritance between a base class and derived class (obviously). I am using code-only and the FluentAPI approach for which I have found very little documentation. I have found a couple of docs on vertical inheritance and code-only but very few on managing the discriminator column/value.

S​o ​I have been trying to extrapolate how to do it from a combination of this blog post and some documentation on implementing vertical inheritance using code-only. All to no avail. 

 I am also providing a link to my DB Diagram (easier than typing in all that code and easier to read). 

You will see that I have a "Deliverables" base table and "PrintDeliverables" derives from that. There will be other "Deliverable" derivatives coming down the road. But I figured I would start with one first.

Anyway, I naturally have models that map to the tables.

01.public class PrintDeliverable : BDeliverableBase
02.{
03.    public String PaperItemNumber { get; set; }
04. 
05.    public String PrinterModel { get; set; }
06.     
07.    public Boolean? ColorOption { get; set; }
08. 
09.    public String ProductCode { get; set; }
10. 
11.}  
12. 
13.public class BDeliverableBase : BModelBase, IDeliverable, ISingleID
14.{
15.    public Int64 ID { get; set; }
16. 
17.    public String Label { get; set; }
18. 
19.    public String Description { get; set; }
20. 
21.    public IList<DeliverableAttribute> Attributes { get; set; }
22. 
23.    public Int64 TypeID { get; set; }
24.    public DeliverableType Type { get; set; }
25. 
26.}
27. 
28.public class DeliverableType : BModelBase, ISingleID
29.{
30.     
31.    public Int64 ID { get; set; }
32. 
33.    public String Label { get; set; }
34. 
35.    public String Description { get; set; }
36. 
37.    public IList<BDeliverableBase> Deliverables { get; set; }
38.}


I have the standard mapping which maps the fields and types, sizes, etc. When I run it with no further additions I get an Error "Invalid Column name voa_class". My research uncovered that the ORM is attempting to update a "discriminator" column with a value that will tie the base table and associated table with the derived data together. So I learned that I can change the name of the column it uses which I did, in the BASE CLASS mapping (BDeliverableBase). I changed it to use the "DeliverableTypeId" column. Since the DeliverableType indicates which TYPE of deliverable it is, each type will have a separate associated table to keep it's type-specific information in, but derived from the Deliverables table.

   MappingConfiguration<BDeliverableBase> map = new MappingConfiguration<BDeliverableBase>();
   map.HasDiscriminator().ToColumn("DeliverableTypeId");


It appears to like this better but it wants to insert this crazy number (ex// 612274703-854) into the "DeliverableTypeId" column which, of course, being a foreign key to the DeliverableTypes table is not allowed. 

Insert of '612274703-' failed: Telerik.OpenAccess.RT.sql.SQLException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_DeliverableType". The conflict occurred in database "DB1", table "dbo.DeliverableTypes", column 'DeliverableTypeId'

I continued my research to learn that OpenAccess/DataAccess generates a hash value to insert into the discriminator column. I do not want this, in fact I know that the value will must one of the ID values available in the DeliverableType. So I read in one of the docs that you could also define what value to assign to the discriminator. The example applied a hard-coded value to the base class (dog and cat derived from animal) ...

   animal.HasDiscriminatorValue("23");

 This presented one problem ... I do not have a single value I can hard-code. It could one of MANY values present in the DeliverableType table. However, for the sake of proving out the concept I hard-coded the value of an existing record in the base class mapping.


   MappingConfiguration<BDeliverableBase> map = new MappingConfiguration<BDeliverableBase>();
   map.HasDiscriminator().ToColumn("DeliverableTypeId");
   map.HasDiscriminatorValue("819");


I continued to get the identical error as before. So it doesn't appear that it was applying my hard-coded value. So ... I thought, while hard-coding the value is a little hacky it would make more sense to define that value in the mapping for the derived class. That would resolve my hard-coded issue since ALL instances of that derived class WOULD indeed be of the same DeliverableTypeId. So I tried ... 

   MappingConfiguration<BDeliverableBase> map = new MappingConfiguration<BDeliverableBase>();
   map.HasDiscriminator().ToColumn("DeliverableTypeId");
 
 
   MappingConfiguration<PrintDeliverable> map = new MappingConfiguration<PrintDeliverable>();
   map.HasDiscriminatorValue("819");


This resulted in the Error

Insert of '612274703-857' failed: Telerik.OpenAccess.RT.sql.SQLException: String or binary data would be truncated.

So I got a different error but still the same poblem. This time it was trying to stuff the ORM generated discriminator value (instead of my 819) into what I am assuming is my defined discriminator column (DeliverableTypeId). The different error makes me suspicious that it was targeting a different column.

In an effort to not drag this out too long, suffice to say I have tried several combinations of where to these "HasDiscriminator" and "HasDiscriminatorValue" assignments go but always end up with one or the other of these errors. So the question is ...

How, using code-only, do I map Vertical Inheritance using multiple, existing "type" values?

 

Thanks in advance!


















5 Answers, 1 is accepted

Sort by
0
Accepted
Ralph Waldenmaier
Telerik team
answered on 15 Sep 2015, 09:13 AM
Hi gstenstrom,
Thank you for contacting us.
Unfortunately, it is not possible to use a lookup table to check which discriminator to assign to a certain derived type. The only way is the one you already figured out, using the HasDiscriminatorValue method.
Attached you can find an example showing how to use this using the fluent mapping approach following your example.

The string truncation error message usually occurs when a string in your persistent object is longer than the size of the column in your database. Can you in your test ensure that you are not exceeding these limitations?

I hope this information is helpful for you.
Do come back in case you need further help.

Regards,
Ralph Waldenmaier
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 15 Sep 2015, 12:37 PM

The problem I am having is that even though I am specifying the Discriminator value ..

   MappingConfiguration<PrintDeliverable> map = new MappingConfiguration<PrintDeliverable>();
   map.HasDiscriminatorValue("819");

I am STILL getting the error ... 

   Insert of '612274703-857' failed: Telerik.OpenAccess.RT.sql.SQLException: String or binary data would be truncated.

Since I am specifying 819 as the discriminator value ​I do not understand why it is even attempting to insert the hash value. Any ideas?

 

 

 

0
Gary
Top achievements
Rank 1
answered on 15 Sep 2015, 01:08 PM

Here's a little more of how the actual code is written ... for your reference. I cannot see what is different between this and the example you sent. 

 

001.public partial class CatalogAdminDbCtxtMetadataSource : FluentMetadataSource
002.{
003.    protected override IList<MappingConfiguration> PrepareMapping()
004.    {
005.        List<MappingConfiguration> configurations = new List<MappingConfiguration>();
006. 
007.        Mapping.DeliverableBaseMapper delivBaseMapper = new DeliverableBaseMapper();
008.        MappingConfiguration<BDeliverableBase> delivBaseMap = delivBaseMapper.Map();
009. 
010.        Mapping.PrintDeliverableMapper printMapper = new PrintDeliverableMapper();
011.        MappingConfiguration<PrintDeliverable> printMap = printMapper.Map();
012. 
013. 
014.        configurations.Add(delivBaseMap);
015.        configurations.Add(printMap);
016. 
017.        return configurations;
018.    }
019.}
020. 
021. 
022.public class PrintDeliverableMapper
023.{
024.    public MappingConfiguration<PrintDeliverable> Map()
025.    {
026.        MappingConfiguration<PrintDeliverable> map = new MappingConfiguration<PrintDeliverable>();
027.        map.MapType(model => new
028.        {
029.            PaperItemNumber = model.PaperItemNumber,
030.            PrinterModel    = model.PrinterModel,
031.            ColorOption     = model.ColorOption,
032.            PrintCode       = model.ProductCode
033. 
034.        })
035.        .Inheritance(Telerik.OpenAccess.InheritanceStrategy.Vertical)
036.        .ToTable("PrintDeliverables");
037.        //
038.        //// Identify the column which defines whihc TYPE this is (i.e. discriminator)
039.        map.HasDiscriminatorValue("819");
040.        //
041.        // Identify contraints on fields
042.        map.HasProperty(c => c.PaperItemNumber).WithVariableLength(25); // nvarchar(25)
043.        map.HasProperty(c => c.PrinterModel).WithVariableLength(100);   // nvarchar(100)
044.        map.HasProperty(c => c.ProductCode).WithVariableLength(50);     // nvarchar(50)
045.         
046.        return map;
047.    }
048.}
049. 
050.public class DeliverableBaseMapper
051.{
052.    public MappingConfiguration<BDeliverableBase> Map()
053.    {
054.        MappingConfiguration<BDeliverableBase> map = new MappingConfiguration<BDeliverableBase>();
055.        map.MapType(model => new
056.        {
057.            DeliverableId           = model.ID,
058.            DeliverableLabel        = model.Label,
059.            DeliverableDescription  = model.Description,
060.            DeliverableTypeId       = model.TypeID,
061.            IsEnabled               = model.IsEnabled
062. 
063.        }).ToTable("Deliverables");
064.        //
065.        // Identify the column which defines which TYPE this is (i.e. discriminator)
066.        map.HasDiscriminator().ToColumn("DeliverableTypeId");
067. 
068.        #region map columns
069. 
070.        map.HasProperty(c => c.ID)
071.            .HasColumnType("bigint")
072.            .IsNotNullable()
073.            .IsIdentity(KeyGenerator.Autoinc);
074. 
075.        map.HasProperty(c => c.Label)
076.            .HasColumnType("nvarchar"
077.            .WithVariableLength(100)
078.            .IsNotNullable();
079. 
080.        map.HasProperty(c => c.Description)
081.            .HasColumnType("nvarchar")
082.            .WithInfiniteLength()
083.            .IsNullable();
084. 
085.        map.HasProperty(c => c.TypeID)
086.            .HasColumnType("bigint")
087.            .IsNotNullable();
088. 
089.        map.HasProperty(c => c.IsEnabled)
090.            .HasColumnType("bit")
091.            .IsNotNullable();
092. 
093.        #endregion map columns
094. 
095.        #region Navigation Properties
096. 
097.        map.HasAssociation(d => d.Type)
098.            .WithOpposite(t => t.Deliverables)
099.            .HasConstraint((d, t) => d.TypeID == t.ID)
100.            .IsManaged(true);
101. 
102.        #endregion Navigation Properties
103. 
104.        return map;
105.    }
106.}
 

 

0
Gary
Top achievements
Rank 1
answered on 15 Sep 2015, 01:35 PM

It appears that the String truncation problem was, as you suggested, a field length issue unrelated to the Discriminator. However the error confused me (and still does) as the value it suggested it was trying to put in the field was not among the values being inserted. Therefore, I assumed that it was generated and related to the Discriminator issue. I still do not know where it was coming from but after some SQL Profiling I was able see the values being passed in and discovered the problem.

 

Thanks for all the help!

0
Ralph Waldenmaier
Telerik team
answered on 16 Sep 2015, 09:27 AM
Hi gstenstrom,
I am glad that you were able to fix the previously reported issues.

Do no hesitate to contact us again in case you need further assistance.

Regards,
Ralph Waldenmaier
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
Ralph Waldenmaier
Telerik team
Gary
Top achievements
Rank 1
Share this question
or