Entity Framework 6, many X many relationship and Scaffolding

1

I am doing a college project and my knowledge in ASP.Net is not very deep. In my project I came across a MxM relationship and I can not implement this situation in a useful way. The relationship is as follows:

  • A company registers one or more garbage collection points and at the time of registration it chooses one or more garbage type accepted in your collection point.

  • A type of garbage can be used in the collection of various collection points.

  • A collection point can associate various types of garbage that are accepted.

I have tried in many ways indicated here on this site. I have tried here and creating the associative class manually, but in scaffolding Entity does not generate the relation in the view.

Doing as indicated at this link Here , The Entity Framework generated the associative table automatically, but in scaffolding the views were created with no association. In 1xN relations Entity automatically creates a dropdowlist to be selected in the view.

  • In the MxM relation you should not automatically create a group of checkbox or a selection list? (or I'm expecting too much from the Entity ...).

  • If you can not generate this feature automatically, how would you do it This?

  • After generating the checkbox group or selection list, how do to manipulate the associative table? (the table of the class in question Entity has already created CRUD).

  • Follow the code:

    [Table("PontoDeColeta")]
    public class PontoDeColeta
    {
        public PontoDeColeta()
        {
            TipoDeLixo = new HashSet<TipoDeLixo>();
        }
    
        public int Id { get; set; }
    
        [Required(ErrorMessage = "O prenchimento é obrigatório")]
        [Display(Name = "Nome popular*: ")]
        public string NomePopular { get; set; }
    
        [Required(ErrorMessage = "O prenchimento é obrigatório")]
        [Display(Name = "Endereço do ponto de coleta*: ")]
        public string Endereco { get; set; }
    
        //Armazena usuário logado
        [HiddenInput(DisplayValue = false)]
        public string UsuarioResponsavel { get; set; }
    
        public ICollection<TipoDeLixo> TipoDeLixo { get; set; }
    }
    [Table("TipoDeLixo")]
    public class TipoDeLixo
    {
        public TipoDeLixo()
        {
            PontoDeColeta = new HashSet<PontoDeColeta>();
        }
        //[Key]
        //[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
    
        [Required(ErrorMessage ="O prenchimento é obrigatório")]
        [Display(Name = "Nome do tipo de lixo*: ")]
        public string NomeTipoLixo { get; set; }
    
        [Display(Name = "Este tipo de lixo está ativo? ")]
        public bool Ativo { get; set; }
    
        public ICollection<PontoDeColeta> PontoDeColeta { get; set; }
    }
    

    Edit : Following the best response of the comment, I had to change my classes besides creating the associative class manually.

    public class TipoDeLixo{
        public Guid Id { get; set; }
    
    
        [Required(ErrorMessage ="O prenchimento é obrigatório")]
        [Display(Name = "Nome do tipo de lixo*: ")]
        public string NomeTipoLixo { get; set; }
    
        [Display(Name = "Este tipo de lixo está ativo? ")]
        public bool Ativo { get; set; }
    
    
        public ICollection<PontoDeColetaTipoDeLixo> PontosDeColetaTiposDeLixo {  get; set; }
    
    }
    
    public class PontoDeColeta{
        public Guid Id { get; set; }
    
        [Required(ErrorMessage = "O prenchimento é obrigatório")]
        [Display(Name = "Nome popular*: ")]
        public string NomePopular { get; set; }
    
        public ICollection<PontoDeColetaTipoDeLixo> PontosDeColetaTiposDeLixo { get; set; }
         }
    
    public class PontoDeColetaTipoDeLixo{
    
        public Guid Id { get; set; }
    
        public virtual TipoDeLixo TipoDeLixo { get; set; }
    
        public Guid TipoDeLixoId { get; set; }
    
        public virtual PontoDeColeta PontoDeColeta { get; set; }
    
        public Guid PontoDeColetaId { get; set; }
        }
    

    In the Create View of the PointCollect:

     @Html.Partial("_TiposDeLixo",Model.PontosDeColetaTiposDeLixo)
    

    I created the PartialView _LipType with the content:

    @model IEnumerable<IdentitySample.Models.PontoDeColetaTipoDeLixo>
    
    <div class="actions">
    <a class="btn btn-default btn-sm" id="adicionar-tipo-de-lixo">
        Adicionar Tipo de lixo
    </a>
    <script type="text/javascript">
        $("#adicionar-tipo-de-lixo").click(function () {
                    $.get('/PontosDeColeta/NovaLinhaDeTipoDeLixo', function (template) {
                        $("#area-tipos-de-lixo").append(template);
                    });
                });
    </script>
    </div>
    
    <div id="area-tipos-de-lixo">
    @if (Model != null)
    {
        foreach (var lixo in Model)
        {
            @Html.Partial("_LinhaTipoDeLixo", lixo);
        }
    }
    </div>
    

    Then I created the PartiaView _LineTypeLine with the content:

    @model IdentitySample.Models.PontoDeColetaTipoDeLixo
    
    @using (Html.BeginCollectionItem("TipoDeLixo"))
    {
    <div class="form-group">
        @Html.HiddenFor(model => model.Id)
        @Html.HiddenFor(model => model.TipoDeLixoId)
    
        <label class="col-md-1 control-label">Nome</label>
        <div class="col-md-5">
            @Html.TextBoxFor(model => model.TipoDeLixo.NomeTipoLixo, new { @class = "form-control", placeholder = "Nome" })
            @Html.ValidationMessageFor(model => model.TipoDeLixo.NomeTipoLixo, "", new { @class = "text-danger" })
        </div>
        <div class="col-md-2">
            <a class="btn red" onclick="$(this).parent().parent().remove();">Excluir</a>
        </div>
    </div>
    }
    

    And in the PointCollectorController I created Action with the following content:

    public ActionResult NovaLinhaDeTipoDeLixo()
        {
            return PartialView("_TiposDeLixo", new PontoDeColetaTipoDeLixo { Id = Guid.NewGuid() });
        }
    

    So when I run the system, the following error appears:

    The model item passed into the dictionary is of type 'IdentitySample.Models.ColumnPart', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable'1 [IdentitySample.Models.ColumnTypeType] '.

    EDIT : I took a print from the screen with the error. CONTROLLERUPDATEFullControllerCollection:

    namespaceIdentitySample.Controllers{publicclassPontosDeColetaController:Controller{privateApplicationDbContextdb=newApplicationDbContext();//GET:PontosDeColetapublicActionResultIndex(){returnView();}publicActionResultNovaLinhaDeTipoDeLixo(){returnPartialView("_LinhaTipoDeLixo", new PontoDeColetaTipoDeLixo { Id = Guid.NewGuid() });
        }
    
    
        //Lista os potos de coleta de acordo com parametros passados
        public JsonResult Listar(string searchPhrase, int current = 1, int rowCount = 5)
        {
            var Identificacao = User.Identity.GetUserId().ToString();
            var Pontos = (from u in db.PontoDeColeta
                          where u.UsuarioResponsavel == Identificacao
                          select u);
            string Chave = Request.Form.AllKeys.Where(v => v.StartsWith("sort")).First();
    
            string Ordenacao = Request[Chave];
    
            string Coluna = Chave.Replace("sort[", String.Empty).Replace("]",String.Empty);
    
            var Soma = Pontos.Count();
    
            if (!String.IsNullOrWhiteSpace(searchPhrase))
            {
                Pontos = Pontos.Where("NomePopular.Contains(@0) OR Endereco.Contains(@0) OR Cidade.Contains(@0) OR Estado.Contains(@0) OR Apelido.Contains(@0)", searchPhrase);
            }
    
            string ColunaOrdenacao = String.Format("{0} {1}", Coluna, Ordenacao);
    
            var PontoDeColetaPagina = Pontos.OrderBy(ColunaOrdenacao).Skip((current - 1) * rowCount).Take(rowCount);
    
            return Json(new{
                rows = PontoDeColetaPagina.ToList(),
                current = current,
                rowCount = rowCount,
                total = Soma
            }
            , JsonRequestBehavior.AllowGet);
        }
    
        // GET: PontosDeColeta/Details/5
        public ActionResult Details(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            PontoDeColeta pontoDeColeta = db.PontoDeColeta.Find(id);
            if (pontoDeColeta == null)
            {
                return HttpNotFound();
            }
    
            return PartialView(pontoDeColeta);
        }
    
        // GET: PontosDeColeta/Create
        public ActionResult Create()
        {
            var UsuarioLogado = new PontoDeColeta();
            UsuarioLogado.UsuarioResponsavel = User.Identity.GetUserId();
            return View(UsuarioLogado);
        }
    
        // POST: PontosDeColeta/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "Id,NomePopular,Endereco,Cidade,Estado,Latitude,Longitude,Remuneracao,InfoAdicional,Ativo,Apelido,UsuarioResponsavel")] PontoDeColeta pontoDeColeta)
        {
            if (ModelState.IsValid)
            {
                pontoDeColeta.Id = Guid.NewGuid();
                db.PontoDeColeta.Add(pontoDeColeta);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
    
            return View(pontoDeColeta);
        }
    
        // GET: PontosDeColeta/Edit/5
        public ActionResult Edit(Guid? id)
        {
    
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            PontoDeColeta pontoDeColeta = db.PontoDeColeta.Find(id);
            if (pontoDeColeta == null)
            {
                return HttpNotFound();
            }
            pontoDeColeta.UsuarioResponsavel = User.Identity.GetUserId();
            return View(pontoDeColeta);
        }
    
        // POST: PontosDeColeta/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Id,NomePopular,Endereco,Cidade,Estado,Latitude,Longitude,InfoAdicional,Ativo,Apelido,UsuarioResponsavel")] PontoDeColeta pontoDeColeta)
        {
            if (ModelState.IsValid)
            {
                db.Entry(pontoDeColeta).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(pontoDeColeta);
        }
    
        // GET: PontosDeColeta/Delete/5
        public ActionResult Delete(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            PontoDeColeta pontoDeColeta = db.PontoDeColeta.Find(id);
            if (pontoDeColeta == null)
            {
                return HttpNotFound();
            }
            return PartialView(pontoDeColeta);
        }
    
        // POST: PontosDeColeta/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(Guid id)
        {
            PontoDeColeta pontoDeColeta = db.PontoDeColeta.Find(id);
            db.PontoDeColeta.Remove(pontoDeColeta);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
    
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
    }
    
        
    asked by anonymous 15.04.2017 / 23:38

    1 answer

    0
      

    I have tried in many ways indicated here on this site. I have tried here and creating the associative class manually, but in scaffolding Entity does not generate the relation in the view.

    In what sense does it not? If it is a master-detail relationship, it does not really generate. Scaffolding may be somewhat limited in some situations.

      
  • Should not MxM automatically create a checkbox group or a selection list? (or I'm expecting too much from the Entity ...).
  •   

    You're expecting a lot from the Scaffolding engine, in fact. Unfortunately, so far, this implementation is manual. I have tried a few times to produce a Scaffold for this case, but it is quite complicated. I still have not found a satisfactory solution. If I find it, I promise to come back here and propose a solution.

      
  • If you can not generate this feature automatically, how would you do it?
  •   

    Using the BeginCollectionItem package. See here the answers already given about it on the site . This is my best answer .

      
  • After generating the checkbox group or selection list, how do I manipulate the associative table? (the class table in question Entity has already created CRUD).
  •   

    It depends on Controller . If it is a Controller of the association table itself, it is trivial. If it's the Controller of PontoDeColeta , follow my best answer that has examples of how to do it.

    POST EDIT

    All right in your implementation, except this:

    @using (Html.BeginCollectionItem("TipoDeLixo"))
    

    If of% of% is @model , the collection name can not be "Linetype" because there is no navigation property with this name here:

    public class PontoDeColeta
    {
        public Guid Id { get; set; }
    
        [Required(ErrorMessage = "O prenchimento é obrigatório")]
        [Display(Name = "Nome popular*: ")]
        public string NomePopular { get; set; }
    
        public ICollection<PontoDeColetaTipoDeLixo> PontosDeColetaTiposDeLixo { get; set; } // <---- Você quis usar esta propriedade, provavelmente
     }
    

    Then it should be:

    @using (Html.BeginCollectionItem("PontosDeColetaTiposDeLixo"))
    

    POST EDIT 2

    The object going to the Partial View is null. Create needs to be initialized to work.

    // GET: PontosDeColeta/Create
    public ActionResult Create()
    {
        var pontoDeColeta = new PontoDeColeta 
        {
            UsuarioResponsavel = User.Identity.GetUserId(),
            PontosDeColetaTiposDeLixo = new List<PontoDeColetaTipoDeLixo>()
        };
    
        return View(pontoDeColeta);
    }
    

    The error message is a bit treacherous. Because% of_% was null, MVC tries to pass the parent object. This is a fairly common error when using Partials .

        
    21.04.2017 / 21:37