1

Hello had this problem before with another data type. For more details you can see here. Multiplicity constraint violated Entity framework 5

But now that solution doesn't work or any other found on the net.

My classes are:

namespace Prometheus.Models
{
    [Table("People")]
    public class Person : IPerson, INamedEntity
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public virtual int Id { get; set; }
        [DisplayName("Prenume")]
        public virtual string FirstName { get; set; }
        [DisplayName("Nume")]
        public virtual string LastName { get; set; }

        public string Name
        {
            get
            {
                return FirstName + " " + LastName;
            }
            set { }
        }
        [DisplayName("Email")]
        public virtual string Email { get; set; }
        public DateTime? LastModified { get; set; }
        public virtual ICollection<Result> Results { get; set; }
        public virtual ICollection<Project> Projects { get; set; }
    }
}

And

public class Project :INamedEntity
{

    public int Id { get; set; }
    public DateTime? LastModified { get; set; }
    [DisplayName("Titlu Proiect")]
    [Required]
    public string Name { get; set; }//Title
    [Required]
    [DisplayName("Tip proiect")]
    public virtual ProjectType ProjectType{ get; set; }
    [DisplayName("Status proiect")]
    public virtual ProjectStatus ProjectStatus { get; set; }
    [Required]
    [DisplayName("Tip program")]
    public virtual ProgramType ProgramType { get; set; }
    [Required]
    [DisplayName("Numar luni")]
    public int NumberOfMonths { get; set; }
    [Required]
    [DisplayName("Project title")]
    public string NameEn { get; set; }
    [Required]
    [DisplayName("Acronim")]
    public string Acronym { get; set; }
    [Required]
    [DisplayName("Numar contract")]
    public string ContractNo { get; set; }
    [Required]
    [DisplayName("Domeniu de activitate")]
    public virtual ActivityField ActivityField {get;set;}
    [Required]
    [DisplayName("Summary")]
    public string SummaryEn { get; set; }
    [Required]
    [DisplayName("Rezumat")]
    public string SumarryRo { get; set; }
    [Required]
    [DisplayName("Data inceput")]
    public virtual DateTime StartDate { get; set; }
    [Required]
    [DisplayName("Data sfarsit")]
    public virtual DateTime EndDate { get; set; }
    [Required]
    [DisplayName("Institutie coordonatoare")]
    public virtual string CoordInstitution { get; set; }
    [DisplayName("Valoare totala proiect")]
    public decimal TotalValue { get; set; }
    [DisplayName("Valuta")]
    public virtual Currency Currency { get; set; }
    [DisplayName("Rol in proiect")]
    public virtual RoleInProject RoleInProject { get; set; }//coord proiect/partener/in afara inst
    [DisplayName("Echipa proiect")]
    public virtual ICollection<Person> People { get; set; }
    [DisplayName("Director proiect")]
    public virtual Person ProjectManager { get; set; }
    public virtual ICollection<Institution> Partners { get;set;}
    public virtual Person PersonInCharge { get; set; }

    [DisplayName("Functie/Rol Expert In Proiect")]
    public string UserFunctionInProject { get; set; }
    [DisplayName("Pagina proiectului")]
    [Required]
    public string Website {get;set;}
    public virtual ICollection<Result> Results { get; set; }
}

When i had the previous problem it was with a class Result and the same Person and was told that if i want a many-to-many relationship i have to add a Collection to Person and a Collection to Result and that did the trick.

But now as you can see i already have

public virtual ICollection<Person> People { get; set; } in Project

and

public virtual ICollection<Project> Projects { get; set; } in Person

And every time i try to add more than one User to the project i get the error in that title when calling the Save() method from DbContext

I have no idea what to do. Thanks.

Accidentally posted the wrong class, it was the result instead of the Person, now it's correct

Update 1

public void AddProjectForUsers(IEnumerable<int> userIds, Project project)
{
    foreach (var id in userIds)
    {
        AddProjectForUser(id,project);
    }
}

public void AddProjectForUser(int userId, Project project)
{
    var user = _ctx.Users.SingleOrDefault(u => u.Id == userId);
    if (user != null)
    {
        if (!user.Projects.Contains(project))
        {
            user.Projects.Add(project);
        }
    }
}

public bool Save()
{
    return _ctx.SaveChanges() > 0; // the error is thrown here
}

The 3 are from my repository class

And the call to them is

Repo.AddProjectForUsers(team, project);
Repo.Save();

Where team is an IEnumerable<int> and project is of type Project

Community
  • 1
  • 1
Bobby Tables
  • 2,953
  • 7
  • 29
  • 53
  • Do you have a fluent mapping here, or is all of your mapping done with dataannotations? It looks like EF thinks the person you are trying to add is either ProjectManager or PersonInCharge. Post your O/R mapping code if there is any more other than what you have already provided. – danludwig Feb 12 '14 at 15:56
  • @danludwig no fluent mapping just some dataannotations. – Bobby Tables Feb 12 '14 at 16:00
  • ... and you don't have any foreign key properties for PersonInCharge or ProjectManager... post the code leading up to where the exception is thrown. Also, what do the foreign keys look like in the database? You have 3 of them, yes? One for the PM, one for the PIC, and another for the projects gerund table? – danludwig Feb 12 '14 at 16:03
  • @danludwig updated my code with functions that lead to the error, i didn't paste the entire class and controller. – Bobby Tables Feb 12 '14 at 16:22
  • So `_ctx.Users` is a `DbSet`? Also, would still like to see your db FK's. You have 3 relations from Project to Person, but only 1 relation from Person to Project, which could be related. – danludwig Feb 12 '14 at 16:25
  • @danludwig sorry just saw the finally part of you comment yes there are 3 of them the 2 you mentioned and the third which is a collection that represents the people that are in the project – Bobby Tables Feb 12 '14 at 16:26
  • @danludwig no it actually of a class that inherits Profile, if you want i can post that as well – Bobby Tables Feb 12 '14 at 16:27

1 Answers1

3

It looks like you may need the InverseProperty data annotation attribute to do this:

namespace Prometheus.Models
{
    [Table("People")]
    public class Person : IPerson, INamedEntity
    {
        ...
        [InverseProperty("People")]
        public virtual ICollection<Project> Projects { get; set; }
    }
}

public class Project :INamedEntity
{
    ...
    [DisplayName("Echipa proiect")]
    [InverseProperty("Projects")]
    public virtual ICollection<Person> People { get; set; }
}

The exception message you are receiving is very telling. Since EF is complaining that the relation is expected to be a one-to-zero-or-one, this leads me to believe that EF is confusing the People - Projects association with either the PersonInCharge - Project or ProjectManager - Project association.

One way to solve this would be to expose foreign key properties on your Project entity, which you should be doing anyway - you can get weird transient errors when you don't. Another way would be to use the fluent API (a.k.a. model builder) instead of data annotations.

Community
  • 1
  • 1
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • Thank you so much, it works. Can you please tell me where you learned about this or is it just experience ? – Bobby Tables Feb 12 '14 at 17:08
  • @toby I just googled for "EF many to many data annotations" and I think it was the second search result. I never use data annotations, only fluent API, so it is not experience. I would have answered your question much more quickly if you were using the fluent mapping API. – danludwig Feb 12 '14 at 17:14