This project has moved. For the latest updates, please go here.

Table Inheritance

Jun 2, 2014 at 1:37 PM
Hi,

we have model with table inheritance. Entity customer inherits form entity User. After generating class Customer inherits from class User. This is ok. But in class Customer is this method and this method causes build error:

protected override bool IsKeyEqual(Customer entity)
    {
        return false;
    }
How can I stop generating this method?

Thanks.
Jun 2, 2014 at 2:13 PM
I changed NTierEF.EntityTT.CS.ttinclude and all works fine. :)
Jun 2, 2014 at 3:14 PM
there was another problem. :( Table inheritance is not supported.: (
Coordinator
Jun 4, 2014 at 9:45 PM
Edited Jun 4, 2014 at 9:49 PM
Thanks for your message.

I've fixed NTierEF.EntityTT.CS.ttinclude to not generate IsKeyEqual and GetKeyHashCode for subtypes.
see: https://ntieref.codeplex.com/SourceControl/changeset/ae7200915da8b6c6b2853fcc2329269708878d5d

I'm not sure what you mean by 'table inheritance is not supported'.
Please note, EF typically only generates entity-sets for base types which is also serve sub-types. This should be no different for n-tier ef.
Jul 18, 2014 at 10:12 PM
Indeed after your fix the entities are generated just fine. But 'NTierEF.ClientDataContextTT.CS.ttinclude' still seems to output the code which doesn't compile for the navigation property 'Cage.Mouse' of type 'Mouse' derived from 'Animal'.

Is there any sample project where one could see how NTierEF copes with inheritance?

Thanks
Coordinator
Aug 12, 2014 at 12:09 AM
You're right, it wasn't only the generated entity classes preventing from successfully using table inheritance.
After fixing several issues I got a sample application working. Can you please try version 1.5 Beta 3 and let me know should you still encounter issues when applying table inheritance. Thanks.
Aug 12, 2014 at 9:23 AM
Hi,

generating works fine. Now I found another problem. I have table "Parent" a tables "Child" and "Child2". I added records to both tables. But if I load items from server, I get exception "Object of type Child cannot be cast to object of type Child2". It looks, that "OfType" not working correctly.

Example:
using (AdventureWorksDataContext context = new AdventureWorksDataContext())
            {
                Child c =new Child();
                c.Id = Guid.NewGuid();
                c.Name = "Test3";
                c.CreateDate = DateTime.Now;
                c.Created = "System";

                context.Parents.Add(c);

               

               
                Child2 child2 = new Child2();
                child2.Id = Guid.NewGuid();
                child2.CreateDate = DateTime.Now;
                child2.Created = "System";
                child2.Age = 1;

                context.Parents.Add(child2);

                context.SaveChanges();

                var c2 = context.Parents.AsQueryable().OfType<Child2>().FirstOrDefault(); ---- Exception
                var c2 = context.Parents.OfType<Child2>().FirstOrDefault(); ---- Works fine


                context.Delete(c1);
                context.SaveChanges();




            }
Coordinator
Aug 14, 2014 at 11:47 PM
You're right - the OfType<T>() function was missing for backend queries. I've added this feature in 1.5 Beta 4.
Can you please upgrade your solution and let me know whether it works:
PM> update-package -pre
Aug 25, 2014 at 12:50 PM
Works.

Thanks. :)
Aug 28, 2014 at 3:05 PM
I've run into an error associated with this (table inheritance). In the generated DataContext class, I receive a number of errors when working with the navigation properties of derived types. In the AttachWithRelations methods, in the "attach relations recursively" region, I am missing an explicit cast from the base type into the derived type. Otherwise, it cannot recognize the navigation properties associated only with the derived type. I'll give an example of one of these from my code below:
// attach related entity to context
            if (entity.AirfoilOutput != null)
            {
                var existingRelatedEntity = AttachWithRelations(entity.AirfoilOutput, insertMode, mergeOption, referenceTrackingList);
                // update relation if entity is new to context or relation is new to entity
                if (existingEntity == null || !entity.AirfoilOutput.Equals(existingEntity.AirfoilOutput))
                {
                    if (existingRelatedEntity != null && !object.ReferenceEquals(existingRelatedEntity, entity.AirfoilOutput))
                    {
                        // check merge options
                        if (!(mergeOption == MergeOption.PreserveChanges && existingRelatedEntity.ChangeTracker.OriginalValues.ContainsKey("AirfoilDataFile")))
                        {
                            using (entity.ChangeTrackingPrevention())
                            {
                                entity.AirfoilOutput = existingRelatedEntity; // ERROR OCCURS HERE
                            }
                            using (existingRelatedEntity.ChangeTrackingPrevention())
                            {
                                existingRelatedEntity.AirfoilDataFile = entity; // ERROR OCCURS HERE
                            }
                        }
                    }
                }
            }
It's not a huge deal to go back and insert the casts after it is generated, but it's something maybe to include in future releases?
Aug 28, 2014 at 6:05 PM
FYI, I was able to resolve this issue by adding if-statements before the 5 spots where this error occured, checking for a base type in the navigation property:

at line 462:
<#+
    if (navProperty.TypeUsage.EdmType.BaseType != null)
    {
#>
                                entity.<#=EdmUtility.Code.Escape(navProperty)#> = (<#=EdmUtility.Code.Escape(navProperty)#>)existingRelatedEntity;
                            }
<#+
    }
    else
    {
#>
                                entity.<#=EdmUtility.Code.Escape(navProperty)#> = existingRelatedEntity;
                            }
<#+
The "else" is simply the normal code, the "if" adds a cast to the existingRelatedEntity. The existingRelated Entity also needed casts at these spots (I'm quoting original code):
var entityToReplace = existingRelatedEntity.<#=EdmUtility.Code.Escape(inverse)#>.FirstOrDefault(e => e.Equals(entity));
existingRelatedEntity.<#=EdmUtility.Code.Escape(inverse)#>.Remove(entityToReplace);
existingRelatedEntity.<#=EdmUtility.Code.Escape(inverse)#>.Add(entity);
existingRelatedEntity.<#=EdmUtility.Code.Escape(inverse)#> = entity;
Coordinator
Sep 16, 2014 at 9:56 PM
Dear joebecar

Thank you very much for reporting this issue and sharing the code snipped.

In the fix to the T4 template I'm casting the result of subsequent calls to AttachWithRelations, rather than multiple casts to 'existingRelatedEntity'.
Be carefull when using (<#=EdmUtility.Code.Escape(navProperty)#>) for the cast as the name of the property might be different from its type.

Thanks.