Pinch
Pinch

Reputation: 4207

Proper Mapping in Code First (Do I smell a many to many?)

Here is the abstract concept of my model:

public class Apple
{    
    public int AppleID {get;set;} 
    public virtual IEnumerable<Banana> Bananas {get;set;}   
}

public class Banana 
{    
    public int BananaID {get;set;}
    public int AppleID {get;set;}
    public virtual Apple Apple {get;set;}    
}

Now let's say that even though that one Apple has many Bananas.

What if a Banana would have a second Different Apple of its own?

Am I missing something. (Less than 4hours of sleep last night)

I can't add modify Banana to look like this:

public class Banana 
{    
    public int BananaID {get;set;}
    public int AppleID {get;set;}
    public virtual Apple Apple {get;set;}    
    public int AnotherAppleID {get;set;}
    public virtual Apple AnotherApple {get;set;}  
}

For clarification "this is kinda looks like a parent / child relationship where each child has exactly one mother and one father, but parents may have many children " - P.S.W.G

Upvotes: 2

Views: 106

Answers (1)

p.s.w.g
p.s.w.g

Reputation: 149010

Well, there are only two solutions I can think of at the moment. The first would require two different relationships. I'm going to rename your classes so it comes out a bit more clearly:

public class Parent
{    
    [Key]
    public int ParentID {get;set;}

    [InverseProperty("Father")]
    public virtual ICollection<Child> FatherOf {get;set;}

    [InverseProperty("Mother")]
    public virtual ICollection<Child> MotherOf {get;set;}
}

public class Child 
{    
    [Key]
    public int ChildID {get;set;}

    [ForeignKey("Father")]
    public int FatherID {get;set;}
    public virtual Parent Father {get;set;}

    [ForeignKey("Mother")]
    public int MotherID {get;set;}
    public virtual Parent Mother {get;set;}
}

Unfortunately, this means you'll have to make to two different checks every time you want to see if a parent has a particular child. Also, you'd have to write a custom entity validation routine if you want to ensure that a child.Mother != child.Father. Of course, you could make a property that represents both sets, like this:

[NotMapped]
public IEnumerable<Child> Children 
{
    get { return this.FatherOf.Concat(this.MotherOf); } 
}

But you won't be able to use this in Linq-to-Entities queries.

The alternative, which may be simpler in the long run is to have a conventional many-to-many relationship:

public class Parent
{    
    public int ParentID {get;set;}
    public virtual ICollection<Child> Children {get;set;}
}

public class Child 
{    
    public int ChildID {get;set;}
    public virtual ICollection<Parent> Parents {get;set;}
}

And now write a custom entity validation routine to ensure that Parents.Count() == 2. The only problem here is that you won't be able to refer to the parents individually within Linq-to-Entities (at least not easily). But, as above, you make your unmapped properties to provide more convenient access to each parent individually once it's loaded into memory.

Caveat lector: I have not tested the above code, and it's entirely possible I'm missing a necessary attribute here or there.

Upvotes: 3

Related Questions