So I'm in the middle of a project where I need to have a Many-to-Many relationship between Teams and Members.
One team can have many users (from aspnetusers) and a user can have 0 or more teams.
But at the moment, One team can have many users, but one user can only have 1 team, whenever I try to add a user on a new team, that user is removed from team he's already in.
I've reached this point thanks to http://cpratt.co/associating-related-items-in-a-collection-via-a-listbox/
My Team Model:
public class EquipaModel
{
[Key]
public int EquipaID { get; set; }
[Required]
[Display (Name="Nome")]
public string EquipaNome { get; set; }
[Required]
[Display (Name="Descrição")]
public string EquipaDescricao { get; set; }
[Display(Name = "Team Manager")]
public string TeamManagerId { get; set; }
public virtual ApplicationUser TeamManager { get; set; }
public virtual ICollection<ApplicationUser> Membros { get; set; }
}
My extended user model
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager
.CreateIdentityAsync(this,
DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
public virtual Utilizador Utilizador { get; set; }
}
[Table("Utilizadores")]
public class Utilizador
{
public int Id { get; set; }
public string PrimeiroNome { get; set; }
public string Apelido { get; set; }
public int Pontuacao { get; set; }
public int PaisID { get; set; }
public virtual PaisModel Pais { get; set; }
//public IEnumerable<LinguasProgModel> Linguagens { get; set; }
}
My Team ViewModel
public class EquipasViewModel
{
[Required]
public string EquipaNome { get; set; }
public string EquipaDescricao { get; set; }
public string TeamManagerId { get; set; }
public virtual ApplicationUser TeamManager { get; set; }
[Required]
public List<string> MembrosID { get; set; }
public IEnumerable<SelectListItem> MembrosEscolhidos { get; set; }
}
My Create on EquipaController (TeamController)
public ActionResult Create()
{
ViewBag.TeamManagerId = new SelectList(db.Users, "Id", "Email");
var model = new EquipasViewModel();
PopulateMembrosEscolhidos(model);
return View(model);
}
[HttpPost]
public ActionResult Create(EquipasViewModel model)
{
if (ModelState.IsValid)
{
var equipa = new EquipaModel
{
EquipaNome = model.EquipaNome,
EquipaDescricao = model.EquipaDescricao,
TeamManagerId = model.TeamManagerId,
Membros = db.Users.Where(m => model.MembrosID.Contains(m.Id)).ToList()
};
db.Equipas.Add(equipa);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.TeamManagerId = new SelectList(db.Users, "Id", "Email", model.TeamManagerId);
PopulateMembrosEscolhidos(model);
return View(model);
}
and finally the Edit on my team controller
public ActionResult Edit(string id)
{
ViewBag.TeamManagerId = new SelectList(db.Users, "Id", "Email");
var equipa = db.Equipas.FirstOrDefault(e => e.EquipaNome == id);
if (equipa == null)
{
return new HttpNotFoundResult();
}
var model = new EquipasViewModel
{
EquipaNome = equipa.EquipaNome,
EquipaDescricao = equipa.EquipaDescricao,
MembrosID = equipa.Membros.Select(m => m.Id).ToList()
};
PopulateMembrosEscolhidos(model);
return View(model);
}
[HttpPost]
public ActionResult Edit(string id, EquipasViewModel model)
{
var equipa = db.Equipas.FirstOrDefault(e => e.EquipaNome == id);
if (equipa == null)
{
return new HttpNotFoundResult();
}
if (ModelState.IsValid)
{
equipa.EquipaNome = model.EquipaNome;
equipa.EquipaDescricao = model.EquipaDescricao;
equipa.Membros.Where(m => !model.MembrosID.Contains(m.Id))
.ToList()
.ForEach(m => equipa.Membros.Remove(m));
var MembrosNaEquipa = equipa.Membros.Select(m => m.Id);
var NovosMembros = model.MembrosID.Except(MembrosNaEquipa);
db.Users.Where(m => NovosMembros.Contains(m.Id))
.ToList()
.ForEach(m => equipa.Membros.Add(m));
db.Entry(equipa).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
PopulateMembrosEscolhidos(model);
return View(model);
}
At some point, I'm going to remove the selectlist and replace it for a textbox where the user inputs user names to add to the memberlist of the team - but at the moment i'm just trying to figure out how to save the many-to-many relationship.
Edit
I had that feeling that it was something simple, but just couldn't get there. I started using that solution, but came across an error that to be honest, I've never seen before.
Multiplicity constraint violated. The role 'ApplicationUser_Equipas_Source' of the relationship 'Codings.Models.ApplicationUser_Equipas' has multiplicity 1 or 0..1.
It happens on line "db.Equipas.Add(equipa);" of Create.
It's probably my mistake, since I tried to add a team to the users simply by
var MembrosEscolhidos = db.Users.Where(m => model.MembrosID.Contains(m.Id)).ToList();
foreach (var item in MembrosEscolhidos)
{
item.Equipas.Add(equipa);
}