I have created an entity type that has multiple collection properties that reference items of the same type. In other words, it reflects a single database table in which the rows are arbitrarily grouped, such that a row may appear in multiple groups.
In the following simplified example, the Person
class has Brothers
and Sisters
collection properties that also reference Person
entities:
public class Person
{
public Person()
{
Brothers = new Collection<Person>();
Sisters = new Collection<Person>();
}
[Key]
public string Name { get; set; }
public int Age { get; set; }
public virtual ICollection<Person> Brothers { get; set; }
public virtual ICollection<Person> Sisters { get; set; }
}
Entity Framework seems to think that this is a valid model, but interprets it to create a single PersonPersons
join table, which fails to reflect the separation of brother and sister relationships.
I assume the solution is to use the fluent API to explicitly map separate join tables for the two relationships but, despite extensive experimentation, I have been unable to get this to work.
Any suggestions please?
Thanks, Tim
A self-referencing many-to-many relationship exists when a given record in the table can be related to one or more other records within the table and one or more records can themselves be related to the given record.
Many-to-many relationships require a collection navigation property on both sides. They will be discovered by convention like other types of relationships. The way this relationship is implemented in the database is by a join table that contains foreign keys to both Post and Tag .
A many-to-many relationship is defined in code by the inclusion of collection properties in each of the entities - The Categories property in the Book class, and the Books property in the Category class: public class Book. { public int BookId { get; set; }
By adding this in the DbContext.OnModelCreating method:
UPDATE Added table-naming map according to nameEqualsPNamePrubeGoldberg's comment above:
modelBuilder.Entity<Person>().HasMany(x => x.Brothers).WithMany()
.Map(x => x.ToTable("Person_Brothers"));
modelBuilder.Entity<Person>().HasMany(x => x.Sisters).WithMany()
.Map(x => x.ToTable("Person_Sisters"));
I got this unit test to pass
[TestMethod]
public void TestPersons()
{
var brother = new Person() { Name = "Brother 1", Age = 10 };
var sister = new Person() { Name = "Sister 1", Age = 12 };
var sibling = new Person() { Name = "Sibling 1", Age = 18 };
sibling.Brothers.Add(brother);
sibling.Sisters.Add(sister);
using (var db = new MyDatabase())
{
db.Persons.Add(brother);
db.Persons.Add(sister);
db.Persons.Add(sibling);
db.SaveChanges();
}
using (var db = new MyDatabase())
{
var person = db.Persons
.Include(x => x.Sisters)
.Include(x => x.Brothers)
.FirstOrDefault(x => x.Name.Equals(sibling.Name));
Assert.IsNotNull(person, "No person");
Assert.IsTrue(person.Brothers.Count == 1, "No brothers!");
Assert.IsTrue(person.Sisters.Count == 1, "No sisters");
}
}
That also creates the link tables you're talking about.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With