0

I am facing issue in foriegn key association for the below entites.

For example there are Three entities namely One, Two and Three. Two is depend on One, like that Three is depend on Two .

In Addition Two will many three's and One will have may two's(One to many)

Since Two and Three are depend on One and Two, I used Identifying relationship. But while foreign key mapping i am getting below exception ..

Two_Three_Source_Two_Three_Target: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical

public class One
    {
    public long Id{get;set;}
    public ICollection<Two> TwoList{get;set;}
    }


 public class Two
    {
    public long Id{get;set;}
    public long OneId{ get; set; }
    public ICollection<Three> ThreeList{get;set;}
    }


 public class Three
    {
    public long Id{get;set;}
    public long TwoId{ get; set; }
    }


public class OneMap: BaseEntityMap<One>
    {
        public OneMap()
        {
        this.HasKey(t => t.Id);
         HasMany(t => t.Two).WithRequired().HasForeignKey(t =>  t.OneId);
         ToTable("One");
        }
    }

 public class TwoMap : BaseEntityMap<Two>
    {
        public TwoMap ()
        {
            this.HasKey(t => new { t.Id, t.OneId});
            ToTable("Two");
            HasMany(t => t.ThreeList).WithRequired().HasForeignKey(t => t.TwoId);
        }
    }

public class ThreeMap : BaseEntityMap<Three>
    {
        public ThreeMap ()
        {
            HasKey(t => new { t.Id, t.TwoId});
            ToTable("Three");
        }
    }

I want help to fix this using Fluent Mapping

Edit

The reason i went for this apprach(Identifying Relationship) is to make below line work(To remove child records from db)

one.TwoList.Remove(item)
senshin
  • 10,022
  • 7
  • 46
  • 59
Max_dev
  • 508
  • 7
  • 25
  • Is there any reason why you use a long to store OneId while One.Id is int? – bubi Jul 07 '15 at 09:23
  • Type doesn't matter. Updated the question with long as type – Max_dev Jul 07 '15 at 09:46
  • Ok, int sounds better. Also virtual for lazy loading. – bubi Jul 07 '15 at 10:13
  • The problem with EF is that a child always has to refer to the *full* primary key of its parent, so the deeper the hierarchy the more key columns are required to fulfil EF's requierements. The conclusion is that identifying relationships don't play nice with EF. – Gert Arnold Jul 08 '15 at 22:10

1 Answers1

1

It's not simple to follow the model :) anyway, a problem is in Three. Three needs to have a reference to two. The primary key of Two is One.Id and Id (Two.Id). Another problem is probably in Id of Three (I think that it should be Id, TwoId, OneId but probably is not necessary to make EF work).

Here there is an example.

public class Model9Context : DbContext
{
    public Model9Context(DbConnection connection)
        : base(connection, false)
    { }

    public DbSet<One> Ones { get; set; }
    public DbSet<Two> Twos { get; set; }
    public DbSet<Three> Threes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Configurations.Add(new OneMap());
        modelBuilder.Configurations.Add(new TwoMap());
        modelBuilder.Configurations.Add(new ThreeMap());
    }
}


public class One
{
    public int Id { get; set; }
    public ICollection<Two> TwoList { get; set; }
}


public class Two
{
    public int Id { get; set; }
    public int OneId { get; set; } 
    public virtual One One { get; set; }
    public virtual ICollection<Three> ThreeList { get; set; }
}


public class Three
{
    public int Id { get; set; }
    public int TwoId { get; set; }
    public int OneId { get; set; }
    public virtual Two Two { get; set; }
}


public class OneMap : EntityTypeConfiguration<One>
{
    public OneMap()
    {
        this.HasKey(t => t.Id);
        ToTable("One");
    }
}

public class TwoMap : EntityTypeConfiguration<Two>
{
    public TwoMap()
    {
        this.HasKey(t => new { t.Id, t.OneId });
        ToTable("Two");

        HasRequired(t => t.One).WithMany(t => t.TwoList).HasForeignKey(t => t.OneId);
    }
}

public class ThreeMap : EntityTypeConfiguration<Three>
{
    public ThreeMap()
    {
        HasKey(t => new { t.Id, t.OneId, t.TwoId });
        ToTable("Three");

        HasRequired(t => t.Two).WithMany(t => t.ThreeList).HasForeignKey(t => new {t.OneId, t.TwoId});
    }
}

This is the foreign key that EF defines in DBMS

ALTER TABLE [Three] ADD CONSTRAINT [FK_Three_Two_OneId_TwoId] FOREIGN KEY ([OneId], [TwoId]) REFERENCES [Two] ([Id], [OneId])

EDIT
For completeness, with this mapping the Id field of One is generated as autoincrement by EF while the field Id of Two and Three are not generated as autoincrement.

bubi
  • 6,414
  • 3
  • 28
  • 45
  • Wow, you'r great. I will accept this as the answer for given problem but still it forces me to add another column to the Third table (Three). I dont like to add One as reference in Three instead I can navigate via Two from Three. – Max_dev Jul 07 '15 at 10:36