none
Inheritance and RelationshipManager InvalidOperationException RRS feed

  • Question

  • I have 1 base class and 2 inherited classes:

        public abstract class ComponentVersion
        {
            public Int64 ID { get; set; }
    
            public string Name { get; set; }
    
            public string Description { get; set; }
        }
    
        public class OSBuildVersion : ComponentVersion
        {
        }
    
        public class ApplicationVersion : ComponentVersion
        {
        }

    My fluent API contains the following:

    	public DbSet<ApplicationVersion> ApplicationVersions { get; set; }
    	public DbSet<OSBuildVersion> OSBuildVersions { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity<ComponentVersion>()
                    .Property(c => c.ID)
                    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                modelBuilder.Entity<ComponentVersion>()
                    .Property(c => c.Name)
                    .IsRequired();
    
                modelBuilder.Entity<ComponentVersion>()
                    .Property(c => c.Description)
                    .IsRequired();
    
                modelBuilder.Entity<OSBuildVersion>()
                    .Map
                    (m =>
                        {
                            m.MapInheritedProperties();
                            m.ToTable("OSBuildVersion");
                        }
                    );
    
                modelBuilder.Entity<ApplicationVersion>()
                    .Map
                    (m =>
                        {
                            m.MapInheritedProperties();
                            m.ToTable("ApplicationVersion");
                        }
                    );
            }

    This will create the following 2 tables (I don't want a seperate table for ComponentVersion, because I want ApplicationVersion and OSBuildversion to be able to have the same ID, for example ApplicationVersion.ID = 1 and OSBuildVersion.ID = 1):

    Everything gets created like I want, but when I query for an ApplicationVersion or OSBuildVersion I get the following exception:

    The relationship manager was defined with an owner of type 'ApplicationVersion', which is not compatible with the type 'OSBuildVersion' for the source role 'Version_OSBuildVersion_Target' in the specified relationship, 'Version_OSBuildVersion'.

    Can somebody give me a hint what I am doing wrong?

    Thanks,

    Max


    • Edited by Max Duysens Thursday, February 6, 2014 9:54 AM
    Thursday, January 30, 2014 3:16 PM

Answers

  • Hi Max,

    Below code is my whole working sample.

    public abstract class ComponentVersion
        {
            public int ID { get; set; }
    
            public string Name { get; set; }
        }
    
        public class ApplicationVersion : ComponentVersion
        {
            
            public virtual ICollection<Version> Versions { get; set; }
        }
    
        public class OSBuildVersion : ComponentVersion
        {
            public virtual ICollection<Version> Versions { get; set; }
        }
    
        public class Version
        {
            public int ID { get; set; }
    
    
            public int AppID { get; set; }
    
            public int OSID { get; set; }
    
    
            public virtual ApplicationVersion APP { get; set; }
    
            public virtual OSBuildVersion OS { get; set; }
    }
    

    public class MyDbContext : DbContext
        {
            public DbSet<ApplicationVersion> Apps { get; set; }
    
            public DbSet<OSBuildVersion> OSs { get; set; }
    
            public DbSet<Version> Versions { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity<ApplicationVersion>().Property(a => a.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                modelBuilder.Entity<OSBuildVersion>().Property(a => a.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                modelBuilder.Entity<ApplicationVersion>().HasMany(p => p.Versions).WithRequired(p => p.APP).HasForeignKey(p => p.AppID);
    
                modelBuilder.Entity<OSBuildVersion>().HasMany(p => p.Versions).WithRequired(p => p.OS).HasForeignKey(p => p.OSID);
            }
        }
    

    Good luck.

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, February 10, 2014 8:39 AM
    Moderator

All replies

  • Hi Max,

    The Entity Framework supports three primary inheritance strategies. But from your description, I cannot distinguish which inheritance strategies you are using. Please refer to the following link to choose an Inheritance Strategy. http://blogs.msdn.com/b/alexj/archive/2009/04/15/tip-12-choosing-an-inheritance-strategy.aspx.

    See how to map the TPH Inheritance. http://msdn.microsoft.com/en-us/data/jj591617.aspx#2.4.

    See how to map the TPT Inheritance. http://msdn.microsoft.com/en-us/data/jj591617.aspx#2.5.

    See how to map the TPC Inheritance. http://msdn.microsoft.com/en-us/data/jj591617.aspx#2.6.

    Hope useful.

    Regards,


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, January 31, 2014 2:33 AM
    Moderator
  • Hi Hetro,

    I am using TPC. Since ComponentVersion is an abstract class it does not have a table in the database.  ApplicationVersion and OSBuildVersion do have a table in the database. All this is correctly configured with my fluent API.

    The problem occurs when I am querying the ApplicationVersion for example. That is when I get the above mentioned error.

    Thanks,

    Max

    Friday, January 31, 2014 4:09 PM
  • Hi Max,

    Please post a test project to help me reproducing this issue. Thank you for understanding.

    Regards,


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Wednesday, February 5, 2014 8:31 AM
    Moderator
  • Hi Hetro,

    The problem lies in the (one-to-many) relationship between Version and ApplicationVersion and Version and OSBuildVersion. Apparenty EF6 cannot figure out what it's getting from the database. I find it strange that this is not supported. If it's not supported, is there a workaround for it? This link explains why it is not possible:

    I have created a test project using EF 6.0.2. Below the resulting database:

    I have inserted the following data in the database:

    ApplicationVersion:

    ID = 1, Name = "ApplicationVersion 1"

    ID = 2, Name = "ApplicationVersion 2"

    ID = 3, Name = "ApplicationVersion 3"

    OSBuildVersion:

    ID = 1, Name = "OSBuildVersion 1"

    ID = 2, Name = "OSBuildVersion 2"

    Version:

    ID = 1, ApplicationVersionId = 1, OSBuildVersionId = 1

    ID = 2, ApplicationVersionId = 2, OSBuildVersionId = 1

    ID = 3, ApplicationVersionId = 3, OSBuildVersionId = 1

    ID = 4, ApplicationVersionId = 3, OSBuildVersionId = 2

    Here is the test project code:

    using System;
    using System.Linq;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration.Conventions;
    
    public class Program
    {
        static void Main(string[] args)
        {
            MyContext context = new MyContext();
    
            IList <Version> versions = context.Versions.ToList();
    
            // Returns 4
            Console.WriteLine(versions.Count);
    
            // This line throw the following error:
            // The relationship manager was defined with an owner of type 'ApplicationVersion', which is not compatible with the type 
            // 'OSBuildVersion' for the source role 'Version_OSBuildVersion_Target' in the specified relationship, 
            // 'CodeFirstNamespace.Version_OSBuildVersion'.
            Console.WriteLine(versions [0].ApplicationVersion.Name);
    
            // This line throw the following error:
            // The specified cast from a materialized 'OSBuildVersion' type to the 'ApplicationVersion' type is not valid.
            ApplicationVersion applicationVersion = context.ApplicationVersions.Find(2);
        }
    }
    
    public class MyContext : DbContext
    {
        public MyContext() : base("DefaultConnection") { }
    
        public MyContext(string connectionString) : base(connectionString) { }
    
        public DbSet<Version> Versions { get; set; }
        public DbSet<ApplicationVersion> ApplicationVersions { get; set; }
        public DbSet<OSBuildVersion> OSBuildVersions { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    
            modelBuilder.Entity<ComponentVersion>()
                .Property(c => c.ID)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
            modelBuilder.Entity<ComponentVersion>()
                .Property(c => c.Name)
                .IsRequired();
    
            modelBuilder.Entity<OSBuildVersion>()
                .Map
                (m =>
                {
                    m.MapInheritedProperties();
                    m.ToTable("OSBuildVersion");
                }
                );
    
            modelBuilder.Entity<ApplicationVersion>()
                .Map
                (m =>
                {
                    m.MapInheritedProperties();
                    m.ToTable("ApplicationVersion");
                }
                );
    
            modelBuilder.Entity<Version>()
                .Property(c => c.ID)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
            modelBuilder.Entity<Version>()
                .HasRequired(t => t.ApplicationVersion)
                .WithMany()
                .Map(t => t.MapKey("ApplicationVersionId"));
    
            modelBuilder.Entity<Version>()
                .HasRequired(t => t.OSBuildVersion)
                .WithMany()
                .Map(t => t.MapKey("OSBuildVersionId"));
        }
    }
    
    #region Model classes
    public abstract class ComponentVersion
    {
        public Int64 ID { get; set; }
    
        public string Name { get; set; }
    }
    
    public class ApplicationVersion : ComponentVersion
    {
    }
    
    public class OSBuildVersion : ComponentVersion
    {
    }
    
    public class Version
    {
        public Int64 ID { get; set; }
        public virtual ApplicationVersion ApplicationVersion { get; set; }
        public virtual OSBuildVersion OSBuildVersion { get; set; }
    }
    #endregion

    Thanks,

    Max


    • Edited by Max Duysens Wednesday, February 5, 2014 11:49 AM Link added
    Wednesday, February 5, 2014 11:46 AM
  • Hi Max,

    I think you need to add virtual collection of version into both ApplicatioVersion and OSBuildVersion class. Please see the following code:

      public class ApplicationVersion : ComponentVersion
        {
            public virtual ICollection<Version> Versions { get; set; }
        }
        public class OSBuildVersion : ComponentVersion
        {
            public virtual ICollection<Version> Versions { get; set; }
        }
    

    You can get the whole project from link below:

    http://sdrv.ms/LSzdmF.

    Good Luck.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, February 6, 2014 9:20 AM
    Moderator
  • Hi Hetro,

    I tried your suggestion but that didn't work either. I have removed all fluent API and replaced it by data annotations and that seemed to do the trick. There must be something in my fluent API that is wrong or missing to achieve what I want.

    Below the modified code:

    using System; using System.Linq; using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; using System.Data.Entity.ModelConfiguration.Conventions; using System.ComponentModel.DataAnnotations; public class Program { static void Main(string[] args) { MyContext context = new MyContext(); IList <Version> versions = context.Versions.ToList(); // Returns 4 Console.WriteLine(versions.Count); // No error anymore Console.WriteLine(versions [0].ApplicationVersion.Name);         // No error anymore

    ApplicationVersion applicationVersion = context.ApplicationVersions.Find(2); } } public class MyContext : DbContext { public MyContext() : base("DefaultConnection") { } public MyContext(string connectionString) : base(connectionString) { } public DbSet<Version> Versions { get; set; } public DbSet<ApplicationVersion> ApplicationVersions { get; set; } public DbSet<OSBuildVersion> OSBuildVersions { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); } } #region Model classes public abstract class ComponentVersion { [Key] public int ID { get; set; } [Required] public string Name { get; set; } } [Table("ApplicationVersion")] public class ApplicationVersion : ComponentVersion { } [Table("OSBuildVersion")] public class OSBuildVersion : ComponentVersion { } [Table("Version")] public class Version { [Key] public int ID { get; set; } public int ApplicationVersionId { get; set; } public virtual ApplicationVersion ApplicationVersion { get; set; } public int OSBuildVersionId { get; set; } public virtual OSBuildVersion OSBuildVersion { get; set; } } #endregion


    Thursday, February 6, 2014 2:11 PM
  • Just omit the base class from your DbContext, since you don't want a table for it in TPC.

    public class MyContext : DbContext
    {
        public MyContext() : base("DefaultConnection") { }
    
        public MyContext(string connectionString) : base(connectionString) { }
    
        //public DbSet<Version> Versions { get; set; }
        public DbSet<ApplicationVersion> ApplicationVersions { get; set; }
        public DbSet<OSBuildVersion> OSBuildVersions { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }
    David


    David http://blogs.msdn.com/b/dbrowne/

    Thursday, February 6, 2014 4:47 PM
  • Thanks for your reply David but the Version table is not the problem. In fact I need this table. The problem is that I don't want a ComponentVersion table (it's an abstract class). And I want to have the Version to be able to have 2 properties (complex types or 2 foreign keys to 2 different inherited tables). But apparently this doesn't work in EF6 using fluent API they way I did it.
    Thursday, February 6, 2014 7:45 PM
  • Hi Max,

    Did you try the sample code I provide in my previous post? It works in my side.

    Regards,


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, February 7, 2014 7:14 AM
    Moderator
  • Hi Hetro,

    I tried but it does not work for me. I still get the same exceptions. Below my complete code with your additions added. Can you maybe post your complete code? Then I can have a look what we have different.

    Thanks

    Max

    using System;
    using System.Linq;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration.Conventions;
    
    public class Program
    {
        static void Main(string[] args)
        {
            MyContext context = new MyContext();
    
            IList <Version> versions = context.Versions.ToList();
    
            // Returns 4
            Console.WriteLine(versions.Count);
    
            // This line throw the following error:
            // The relationship manager was defined with an owner of type 'ApplicationVersion', which is not compatible with the type 
            // 'OSBuildVersion' for the source role 'Version_OSBuildVersion_Target' in the specified relationship, 
            // 'CodeFirstNamespace.Version_OSBuildVersion'.
            Console.WriteLine(versions [0].ApplicationVersion.Name);
    
            // This line throw the following error:
            // The specified cast from a materialized 'OSBuildVersion' type to the 'ApplicationVersion' type is not valid.
            ApplicationVersion applicationVersion = context.ApplicationVersions.Find(2);
        }
    }
    
    public class MyContext : DbContext
    {
        public MyContext() : base("DefaultConnection") { }
    
        public MyContext(string connectionString) : base(connectionString) { }
    
        public DbSet<Version> Versions { get; set; }
        public DbSet<ApplicationVersion> ApplicationVersions { get; set; }
        public DbSet<OSBuildVersion> OSBuildVersions { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    
            modelBuilder.Entity<ComponentVersion>()
                .Property(c => c.ID)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
            modelBuilder.Entity<ComponentVersion>()
                .Property(c => c.Name)
                .IsRequired();
    
            modelBuilder.Entity<OSBuildVersion>()
                .Map
                (m =>
                {
                    m.MapInheritedProperties();
                    m.ToTable("OSBuildVersion");
                }
                );
    
            modelBuilder.Entity<ApplicationVersion>()
                .Map
                (m =>
                {
                    m.MapInheritedProperties();
                    m.ToTable("ApplicationVersion");
                }
                );
    
            modelBuilder.Entity<Version>()
                .Property(c => c.ID)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
            modelBuilder.Entity<Version>()
                .HasRequired(t => t.ApplicationVersion)
                .WithMany(t => t.Versions)
                .Map(t => t.MapKey("ApplicationVersionId"));
    
            modelBuilder.Entity<Version>()
                .HasRequired(t => t.OSBuildVersion)
                .WithMany(t => t.Versions)
                .Map(t => t.MapKey("OSBuildVersionId"));
        }
    }
    
    #region Model classes
    public abstract class ComponentVersion
    {
        public Int64 ID { get; set; }
    
        public string Name { get; set; }
    }
    
    public class ApplicationVersion : ComponentVersion
    {
        public virtual ICollection<Version> Versions { get; set; }
    }
    
    public class OSBuildVersion : ComponentVersion
    {
        public virtual ICollection<Version> Versions { get; set; }
    }
    
    public class Version
    {
        public Int64 ID { get; set; }
        public virtual ApplicationVersion ApplicationVersion { get; set; }
        public virtual OSBuildVersion OSBuildVersion { get; set; }
    }
    #endregion

    Friday, February 7, 2014 10:05 AM
  • Hi Max,

    Below code is my whole working sample.

    public abstract class ComponentVersion
        {
            public int ID { get; set; }
    
            public string Name { get; set; }
        }
    
        public class ApplicationVersion : ComponentVersion
        {
            
            public virtual ICollection<Version> Versions { get; set; }
        }
    
        public class OSBuildVersion : ComponentVersion
        {
            public virtual ICollection<Version> Versions { get; set; }
        }
    
        public class Version
        {
            public int ID { get; set; }
    
    
            public int AppID { get; set; }
    
            public int OSID { get; set; }
    
    
            public virtual ApplicationVersion APP { get; set; }
    
            public virtual OSBuildVersion OS { get; set; }
    }
    

    public class MyDbContext : DbContext
        {
            public DbSet<ApplicationVersion> Apps { get; set; }
    
            public DbSet<OSBuildVersion> OSs { get; set; }
    
            public DbSet<Version> Versions { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity<ApplicationVersion>().Property(a => a.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                modelBuilder.Entity<OSBuildVersion>().Property(a => a.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                modelBuilder.Entity<ApplicationVersion>().HasMany(p => p.Versions).WithRequired(p => p.APP).HasForeignKey(p => p.AppID);
    
                modelBuilder.Entity<OSBuildVersion>().HasMany(p => p.Versions).WithRequired(p => p.OS).HasForeignKey(p => p.OSID);
            }
        }
    

    Good luck.

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, February 10, 2014 8:39 AM
    Moderator
  • Thanks Hetro, that worked. The difference is in the fluent API.
    Tuesday, February 11, 2014 11:16 AM