Question

Working with Entity Framework 6, I have a Person class...

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Relationship> Relationships { get; set; }
}

and a Relationship Class

public class Relationship
{
    public int ID { get; set; }
    public RelationshipType DependencyType { get; set; }

    [ForeignKey("Person")]
    public int PersonID { get; set; }
    public virtual Person Person { get; set; }

    public virtual ICollection<Person> RelatedPersons { get; set; }

}

What I want this to represent is that for example I might have Siblings as a relationship type and UnclesAndAunts as another relationship type and hold these types of relationships without the need to know who the parents are as they may not be in the database.

With Code First, this produces a table schema of...

CREATE TABLE [dbo].[Person](
[ID] [int] IDENTITY(1,1) NOT NULL,
 [Name] [nvarchar](max) NULL,
[Relationship_ID] [int] NULL)

and

CREATE TABLE [dbo].[Relationship](
    [ID] [int] IDENTITY(1,1) NOT NULL,
[RelationshipType] [int] NOT NULL,
[PersonID] [int] NOT NULL,
[Person_ID] [int] NULL)

PersonID is the main Person of this relationship.
Person_ID is the Person to whom the main person is related to.
I would see the Relationship table containing repeated PersonID data.

The problem with this is that because of the Relationship_ID in the Person table this is saying that the Person table will have repeated data whereas I want the Relationship table to have the repeated data e.g.

Relationship...

ID   RelationshipType PersonID    Person_ID
---------------------------------------------
1    Sibling           1           2
2    Sibling           1           3
3    UnclesAndAunts    1           4

Can someone tell me how I should represent this with the Model Classes, I assume there are some attributes or other that I need to include.

Thanks

Était-ce utile?

La solution

The Relationship_ID stems from the Relationship.RelatedPersons collection. I think it's not correct to have a collection here, instead it should be a single reference RelatedPerson (singular) since a single Relationship entity describes the relationship between exactly two people, not between a person and a collection of other people. So, I'd propose to change the model like this:

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }

    [InverseProperty("Person")]
    public virtual ICollection<Relationship> Relationships { get; set; }
}

public class Relationship
{
    public int ID { get; set; }
    public RelationshipType DependencyType { get; set; }

    [ForeignKey("Person")]
    public int PersonID { get; set; }
    public virtual Person Person { get; set; }

    [ForeignKey("RelatedPerson")]
    public int RelatedPersonID { get; set; }
    public virtual Person RelatedPerson { get; set; }
}

The [InverseProperty] attribute is important here to tell EF that Relationship.Person is the inverse navigation property of Person.Relationships. Without that attribute you would get three foreign keys in the Relationship table refering to the Person table.

You probably also need to disable cascading delete for one of the relationships to avoid an exception about forbidden multiple cascading delete paths from Person to Relationship. It can be done with Fluent API:

modelBuilder.Entity<Relationship>()
    .HasRequired(r => r.RelatedPerson)
    .WithMany()
    .HasForeignKey(r => r.RelatedPersonID)
    .WillCascadeOnDelete(false);

Once you have that you can add the second relationship with Fluent API as well which would allow you to remove all attributes from the model as they are redundant then:

modelBuilder.Entity<Relationship>()
    .HasRequired(r => r.Person)
    .WithMany(p => p.Relationships)
    .HasForeignKey(r => r.PersonID);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top