envio
envio

Reputation: 1365

Multiple one-to-many relationships with entity framework code first

I am trying to form a relationship of 2 tables to a 3rd, on a 1 to many basis. I have the following code:

    public class CompanyInvolvement
    {
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public DateTime StartDate { get; set; }

    public DateTime? EndDate { get; set; }

    public virtual Person Person { get; set; }
    public virtual Company Company { get; set; }
    }

    public class Person
    {
    public Person()
    {
        CompanyInvolvements = new Collection<CompanyInvolvement>();
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Required]
    public string ClientIdReference { get; set; }

    public virtual ICollection<CompanyInvolvement> CompanyInvolvements { get; set; }
    }


 public class Company
 {
    public Company()
    {
        Involvements = new Collection<CompanyInvolvement>();
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Required]
    public string ClientIdReference { get; set; }

    [Required]
    public string CompanyName { get; set; }

    public virtual ICollection<CompanyInvolvement> Involvements { get; set; }
  }

So effectively a Person can have many involvements in companies and a Company can have many people involved with it. The model builder is used like so:

modelBuilder.Entity<CompanyInvolvement>().HasRequired(x => x.Person).WithMany(x => x.CompanyInvolvements);
modelBuilder.Entity<CompanyInvolvement>().HasRequired(x => x.Company).WithMany(x => x.Involvements);

I originally created the relationship using the modelbuilder, specifying left and right keys (CompanyId and PersonId) and this worked great. But now I need the Start and End dates for an Involvement, I guess I needed to create a dedicated entity.

The question: When I use the above structure, I can create and read out involvements for a company and also see involvements for a Person. However, when I try to do the following:

var person = _context.People.FirstOrDefault(x => x.Id == personId);
var involvement = company.Involvements.FirstOrDefault(x => x.Person == person );
company.Involvements.Remove(involvement);
_context.SaveChanges();

I get the following error:

A relationship from the 'CompanyInvolvement_Company' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a corresponding 'CompanyInvolvement_Company_Source' must also in the 'Deleted' state.

I think my virtual properties in the 3 entities are correct, but I have the feeling the modelbuilder logic I have may be slightly misconfigured?

Upvotes: 0

Views: 742

Answers (1)

envio
envio

Reputation: 1365

I finally figured out what I was doing wrong. I needed to remove the Id property from the CompanyInvolvement entity and add the following composite key:

    [Key, Column(Order = 0)]
    public Guid PersonId { get; set; }

    [Key, Column(Order = 1)]
    public Guid CompanyId { get; set; }

I'm guessing by convention, these two properties were then linked as foreign keys to the Person and Company entities respectively. I also removed the modelbuilder mapping as stated in my original question. Once these were done, deleting CompanyInvolvements worked as expected.

Upvotes: 1

Related Questions