none
code first, one to one relation, inheritance, strange behavior RRS feed

  • Question

  • hello,

    with the following code, EF tries twice to create an index on Organizations (Id)... the second try fails as the index stil exists. I can't understand why EF tries twice.

    If I remove some code first code... all goes on, but the table Bases is not created. Of course the case is an extract of a larger project.

    Thank you in advance for any advice/suggestion

    using System;
    using System.ComponentModel.DataAnnotations;
    using System.Data.Entity;
    
    namespace testef {
        public class Base {
            public int Id { get; set; }
            public DateTime Inserted { get; set; }
            public DateTime LastUpdated { get; set; }
        }
    
        public class Organization : Base {
            public virtual ThirdParty IRLThirdParty { get; set; }
            public String Name { get; set; }
        }
    
        public class ThirdParty {
            public int Id { get; set; }
            public String Name { get; set; }
            public virtual Organization Organization { get; set; }
        }    
    
        class Program {
            static void Main(String[] args) {            
                using (TestEFContext c = new TestEFContext(@"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True")) {
                    foreach(Organization o in c.Organizations) {
                        Console.WriteLine("{0} : {1}", o.IRLThirdParty.Name, o.IRLThirdParty.Organization.Name);                    
                    }
                }
            }
        }
    
        public class TestEFContext : DbContext {
            public IDbSet<ThirdParty> ThirdParties { get; set; }
            public IDbSet<Organization> Organizations { get; set; }
    
            public TestEFContext(String cs)
                : base(cs) {
                Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlwaysWithSeedData());
            }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder) {
                base.OnModelCreating(modelBuilder);
    
                modelBuilder.Entity<Base>().ToTable("Bases");
                modelBuilder.Entity<Base>().HasKey(b => b.Id);
                modelBuilder.Entity<Base>().Property(b => b.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                modelBuilder.Entity<Organization>().ToTable("Organizations");
    
                modelBuilder.Entity<ThirdParty>().ToTable("ThirdParties");
                modelBuilder.Entity<ThirdParty>().HasKey(tp => tp.Id);
                modelBuilder.Entity<ThirdParty>().HasOptional(tp => tp.Organization).WithRequired(o => o.IRLThirdParty);            
            }
    
        }
    
        public class DropCreateDatabaseAlwaysWithSeedData : DropCreateDatabaseAlways<TestEFContext> {
            protected override void Seed(TestEFContext context) {
                base.Seed(context);
    
                ThirdParty tp = new ThirdParty { Name = "tp I" };
                context.ThirdParties.Add(tp);
                context.Organizations.Add(new Organization { Name = "O I", IRLThirdParty = tp, Inserted = DateTime.Now, LastUpdated = DateTime.Now });
            }
        }
    }

    The code that does it well :

    using System;
    using System.ComponentModel.DataAnnotations;
    using System.Data.Entity;
    
    namespace testef {
        public class Base {
            public int Id { get; set; }
            public DateTime Inserted { get; set; }
            public DateTime LastUpdated { get; set; }
        }
    
        public class Organization : Base {
            public virtual ThirdParty IRLThirdParty { get; set; }
            public String Name { get; set; }
        }
    
        public class ThirdParty {
            public int Id { get; set; }
            public String Name { get; set; }
            public virtual Organization Organization { get; set; }
        }    
    
        class Program {
            static void Main(String[] args) {            
                using (TestEFContext c = new TestEFContext(@"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True")) {
                    foreach(Organization o in c.Organizations) {
                        Console.WriteLine("{0} : {1}", o.IRLThirdParty.Name, o.IRLThirdParty.Organization.Name);                    
                    }
                }
            }
        }
    
        public class TestEFContext : DbContext {
            public IDbSet<ThirdParty> ThirdParties { get; set; }
            public IDbSet<Organization> Organizations { get; set; }
    
            public TestEFContext(String cs)
                : base(cs) {
                Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlwaysWithSeedData());
            }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder) {
                base.OnModelCreating(modelBuilder);
    
                //modelBuilder.Entity<Base>().ToTable("Bases");
                //modelBuilder.Entity<Base>().HasKey(b => b.Id);
                //modelBuilder.Entity<Base>().Property(b => b.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    
                //modelBuilder.Entity<Organization>().ToTable("Organizations");
    
                //modelBuilder.Entity<ThirdParty>().ToTable("ThirdParties");
                //modelBuilder.Entity<ThirdParty>().HasKey(tp => tp.Id);
                modelBuilder.Entity<ThirdParty>().HasOptional(tp => tp.Organization).WithRequired(o => o.IRLThirdParty);            
            }
    
        }
    
        public class DropCreateDatabaseAlwaysWithSeedData : DropCreateDatabaseAlways<TestEFContext> {
            protected override void Seed(TestEFContext context) {
                base.Seed(context);
    
                ThirdParty tp = new ThirdParty { Name = "tp I" };
                context.ThirdParties.Add(tp);
                context.Organizations.Add(new Organization { Name = "O I", IRLThirdParty = tp, Inserted = DateTime.Now, LastUpdated = DateTime.Now });
            }
        }
    }

    thierry

    Monday, June 4, 2012 12:33 PM

Answers

  • Hi thierry schmit,

    Welcome to MSDN Forum.

    Based on the first code snip, the models are not valid, so the exception is thrown. 'Organization' entity is derived from 'Base' entity, 'Base' entity has a primary key and it is identity column, so the primary key of 'Organization' is also identity. But the relationship between 'Organization' and 'ThirdParty' is one to one, the 'ThirdParty' is the principle entity, so the primary key of 'Organization' need to references to the primary key of 'ThirdParty', that means, the primary key of 'Organization' is also a foreign key, but it is identity, so the models are not valid.

    For the second code snip, the Base table will not be generated in database, so there's no exception is thrown. I think it's not the purpose you want to achieve.

    Best Regards


    Allen Li [MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, June 5, 2012 7:05 AM
    Moderator

All replies

  • Hi thierry schmit,

    Welcome to MSDN Forum.

    Based on the first code snip, the models are not valid, so the exception is thrown. 'Organization' entity is derived from 'Base' entity, 'Base' entity has a primary key and it is identity column, so the primary key of 'Organization' is also identity. But the relationship between 'Organization' and 'ThirdParty' is one to one, the 'ThirdParty' is the principle entity, so the primary key of 'Organization' need to references to the primary key of 'ThirdParty', that means, the primary key of 'Organization' is also a foreign key, but it is identity, so the models are not valid.

    For the second code snip, the Base table will not be generated in database, so there's no exception is thrown. I think it's not the purpose you want to achieve.

    Best Regards


    Allen Li [MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, June 5, 2012 7:05 AM
    Moderator
  • hello and thank you,

    I understand the explanation the difficulty is here : so the primary key of 'Organization' need to references to the primary key of 'ThirdParty'.

    My goal is to manage rights on objects, each object having a unique identifier given by the Base class and rights attached to this identifier.

    Each managed object is derived from the Base class.

    From this point I will enforce the one-one constraint out of the model and the loading out of EF (that's bad) but I will consider changing the model even if I think the described model is implementable on SQL server.

    Thank you again

    thierry


    thierry

    Tuesday, June 5, 2012 7:55 AM
  • Hi thierry schmit,

    Yes, based on this issue, we couldn't set a 1 to 1 relationship between the two entities. We can write a wrapper which contains the DBSet.Add method and invoke it after validating.

    Best Regards


    Allen Li [MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, June 5, 2012 8:06 AM
    Moderator