简体   繁体   中英

Many to many relationship ASP.NET MVC and ASP.NET WEB API

So, i have two projects, WebAPI and Client. The Client uses the database of the WebAPI project, and does not have it's own. Everything is working fine in one-to-one relationships and one-to-many relationships. However, i now need to figure out how to make it work with many-to-many relationships. I'll be posting my code, so, to better explain myself i will write with the real class names as you will be able to understand due to the code i will post further.

In my WebApi.Models i have two classes, PlanoManutencao and Ativo. This is a many-to-many relationship. Here are the classes:

    public class PlanoManutencao
{
    public PlanoManutencao()
    {
        Ativos = new List<Ativo>();
        Operacoes = new List<Operacao>();
    }

    public int ID { get; set; }
    public string Nome { get; set; }
    public string Observacoes { get; set; }
    public bool Permanente { get; set; }
    public DateTime DataCriacao { get; set; }

    public virtual ICollection<Ativo> Ativos { get; set; }
    public virtual ICollection<Operacao> Operacoes { get; set; }
}



    public class Ativo
{
    public Ativo()
    {
        PlanosManutencao = new List<PlanoManutencao>();
    }

    public int ID { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }

    public virtual ICollection<PlanoManutencao> PlanosManutencao { get; set; }

}

Now, in my WebAPI i'm using repositories, as follows:

 public class PlanosManutencaoRepository : IPlanosManutencaoRepository
{
    public ApplicationDbContext context;
    public PlanosManutencaoRepository()
    {
        context = new ApplicationDbContext();
    }

    public PlanoManutencao Create(PlanoManutencao planoManutencao)
    {
        context.PlanosManutencao.Add(planoManutencao);
        context.SaveChanges();
        return planoManutencao;
    }

    public bool Delete(int id)
    {
        var planoManutencao = context.PlanosManutencao.Find(id);
        if (planoManutencao != null)
        {
            context.PlanosManutencao.Remove(planoManutencao);
            context.SaveChanges();
            return true;
        }
        else return false;
    }

    public List<PlanoManutencao> GetData()
    {
        var planosManutencao = context.PlanosManutencao.ToList();
        return planosManutencao;
    }

    public List<PlanoManutencao> GetData(DateTime data)
    {
        var planosManutencao = context.PlanosManutencao.Where(f => f.DataCriacao == data);
        return planosManutencao.ToList();
    }

    public PlanoManutencao GetDataById(int id)
    {
        return context.PlanosManutencao.Find(id);
    }

    public bool Update(int id, PlanoManutencao planoManutencao)
    {
        var planoManutencaoAux = context.PlanosManutencao.Find(id);
        if (planoManutencao != null)
        {
            planoManutencaoAux.DataCriacao = planoManutencao.DataCriacao;
            context.SaveChanges();
            return true;
        }
        else return false;
    }
}



 public class AtivosRepository : IAtivosRepository
{
    public ApplicationDbContext context;
    public AtivosRepository()
    {
        context = new ApplicationDbContext();
    }

    public Ativo Create(Ativo ativo)
    {
        context.Ativos.Add(ativo);
        context.SaveChanges();
        return ativo;
    }

    public bool Delete(int id)
    {
        var ativo = context.Ativos.Find(id);
        if (ativo != null)
        {
            context.Ativos.Remove(ativo);
            context.SaveChanges();
            return true;
        }
        else return false;
    }

    public List<Ativo> GetData()
    {
        var ativos = context.Ativos.ToList();
        return ativos;
    }

    public List<Ativo> GetData(string descricao)
    {
        var ativos = context.Ativos.Where(f => f.Descricao == descricao);
        return ativos.ToList();
    }

    public Ativo GetDataById(int id)
    {
        return context.Ativos.Find(id);
    }

    public bool Update(int id, Ativo ativo)
    {
        var ativoAux = context.Ativos.Find(id);
        if (ativo != null)
        {
            ativoAux.Nome = ativo.Nome;
            ativoAux.Descricao = ativo.Descricao;

            context.SaveChanges();
            return true;
        }
        else return false;
    }
}

Now, for the controllers, i have:

 public class PlanosManutencaoController : ApiController
{
    //private ApplicationDbContext db = new ApplicationDbContext();
    private IPlanosManutencaoRepository repoPM = new PlanosManutencaoRepository();


    // GET: api/PlanosManutencao
    public IQueryable<PlanoManutencao> GetPlanoManutencaos()
    {
        return repoPM.GetData().AsQueryable();
    }

    // GET: api/PlanosManutencao/5
    [ResponseType(typeof(PlanoManutencao))]
    public IHttpActionResult GetPlanoManutencao(int id)
    {
        PlanoManutencao planoManutencao = repoPM.GetDataById(id);
        if (planoManutencao == null)
        {
            return NotFound();
        }

        return Ok(planoManutencao);
    }

    // PUT: api/PlanosManutencao/5
    [ResponseType(typeof(void))]
    public IHttpActionResult PutPlanoManutencao(int id, PlanoManutencao planoManutencao)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != planoManutencao.ID)
        {
            return BadRequest();
        }


        bool isSucess = repoPM.Update(id, planoManutencao);

        if (!PlanoManutencaoExists(id))
        {
            return NotFound();
        }

        return Ok();
    }

    // POST: api/PlanosManutencao
    [ResponseType(typeof(PlanoManutencao))]
    public IHttpActionResult PostPlanoManutencao(PlanoManutencao planoManutencao)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (repoPM.Create(planoManutencao) == null)
        {
            return StatusCode(HttpStatusCode.BadRequest);
        }

        return CreatedAtRoute("DefaultApi", new { id = planoManutencao.ID }, planoManutencao);
    }

    // DELETE: api/PlanosManutencao/5
    [ResponseType(typeof(PlanoManutencao))]
    public IHttpActionResult DeletePlanoManutencao(int id)
    {
        PlanoManutencao planoManutencao = repoPM.GetDataById(id);
        if (planoManutencao == null)
        {
            return NotFound();
        }


        bool isSuccess = repoPM.Delete(id);
        if (!isSuccess)
        {
            return StatusCode(HttpStatusCode.BadRequest);
        }

        return Ok();
    }

    private bool PlanoManutencaoExists(int id)
    {
        return repoPM.GetDataById(id) == null ? false : true;
    }
}



public class AtivosController : ApiController
{
    //private ApplicationDbContext db = new ApplicationDbContext();
    private IAtivosRepository repoA = new AtivosRepository();

    // GET: api/Ativos
    public IQueryable<Ativo> GetAtivoes()
    {
        return repoA.GetData().AsQueryable();
    }

    // GET: api/Ativos/5
    [ResponseType(typeof(Ativo))]
    public IHttpActionResult GetAtivo(int id)
    {
        Ativo ativo = repoA.GetDataById(id);
        if (ativo == null)
        {
            return NotFound();
        }

        return Ok(ativo);
    }

    // PUT: api/Ativos/5
    [ResponseType(typeof(void))]
    public IHttpActionResult PutAtivo(int id, Ativo ativo)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != ativo.ID)
        {
            return BadRequest();
        }


        bool isSucess = repoA.Update(id, ativo);

        if (!AtivoExists(id))
        {
            return NotFound();
        }

        return Ok();
    }

    // POST: api/Ativos
    [ResponseType(typeof(Ativo))]
    public IHttpActionResult PostAtivo(Ativo ativo)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (repoA.Create(ativo) == null)
        {
            return StatusCode(HttpStatusCode.BadRequest);
        }

        return CreatedAtRoute("DefaultApi", new { id = ativo.ID }, ativo);
    }

    // DELETE: api/Ativos/5
    [ResponseType(typeof(Ativo))]
    public IHttpActionResult DeleteAtivo(int id)
    {
        Ativo ativo = repoA.GetDataById(id);
        if (ativo == null)
        {
            return NotFound();
        }


        bool isSuccess = repoA.Delete(id);
        if (!isSuccess)
        {
            return StatusCode(HttpStatusCode.BadRequest);
        }

        return Ok();
    }


    private bool AtivoExists(int id)
    {
        return repoA.GetDataById(id) == null ? false : true;
    }
}

Now, as for the Client project, i'm using ViewModels,Controllers and Views. ViewModels:

 public class PlanoManutencaoViewModel
{
    public PlanoManutencaoViewModel()
    {
        Ativos = new List<AtivoViewModel>();
        Operacoes = new List<OperacaoViewModel>();
    }

    public int ID { get; set; }
    [Display(Name = "Name")]
    public string Nome { get; set; }
    [Display(Name = "Observations")]
    public string Observacoes { get; set; }
    [Display(Name = "Permanent")]
    public bool Permanente { get; set; }
    [Display(Name = "Created")]
    public DateTime DataCriacao { get; set; }

    [Display(Name = "Assets")]
    public virtual ICollection<AtivoViewModel> Ativos { get; set; }
    [Display(Name = "Tasks")]
    public virtual ICollection<OperacaoViewModel> Operacoes { get; set; }
}



  public class AtivoViewModel
{
    public AtivoViewModel()
    {
        PlanosManutencao = new List<PlanoManutencaoViewModel>();
    }

    public int ID { get; set; }
    [Display(Name = "Name")]
    public string Nome { get; set; }
    [Display(Name = "Description")]
    public string Descricao { get; set; }

    public ICollection<PlanoManutencaoViewModel> PlanosManutencao { get; set; }
}

The controllers are as follows:

 public class PlanosManutencaoController : Controller
{
    // GET: PlanosManutencao
    public async Task<ActionResult> Index()
    {
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao");
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var planosManutencao =
            JsonConvert.DeserializeObject<IEnumerable<PlanoManutencaoViewModel>>(content);
            return View(planosManutencao);
        }
        else
        {
            return Content("Ocorreu um erro: " + response.StatusCode);
        }
    }

    // GET: PlanosManutencao/Details/5
    public async Task<ActionResult> Details(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao/" + id);
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var plano = JsonConvert.DeserializeObject<PlanoManutencaoViewModel>(content);
            if (plano == null) return HttpNotFound();
            return View(plano);
        }
        else
        {
            return Content("Ocorreu um erro: " + response.StatusCode);
        }
    }

    // GET: PlanosManutencao/Create
    public ActionResult Create()
    {
        PopulateDropDownListForAtivos();
        return View();
    }
    // POST: PlanosManutencao/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 async Task<ActionResult> Create(PlanoManutencaoViewModel planoManutencao)
    {
        try
        {
            PopulateDropDownListForAtivos(planoManutencao.Ativos);
            var client = WebApiHttpClient.GetClient();
            string planoManutencaoJSON = JsonConvert.SerializeObject(planoManutencao);
            HttpContent content = new StringContent(planoManutencaoJSON, System.Text.Encoding.Unicode, "application/json");
            var response = await client.PostAsync("api/PlanosManutencao", content);

            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return Content("Ocorreu um erro: " + response.StatusCode);
            }
        }
        catch
        {
            return Content("Ocorreu um erro.");
        }



    }

    // GET: PlanosManutencao/Edit/5
    public async Task<ActionResult> Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao/" + id);
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var planoManutencao = JsonConvert.DeserializeObject<PlanoManutencaoViewModel>(content);
            if (planoManutencao == null) return HttpNotFound();
            return View(planoManutencao);
        }
        return Content("Ocorreu um erro: " + response.StatusCode);
    }

    // POST: PlanosManutencao/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 async Task<ActionResult> Edit(PlanoManutencaoViewModel planoManutencao)
    {
        try
        {
            var client = WebApiHttpClient.GetClient();
            string planoManutencaoJSON = JsonConvert.SerializeObject(planoManutencao);
            HttpContent content = new StringContent(planoManutencaoJSON, System.Text.Encoding.Unicode, "application/json");
            var response =
            await client.PutAsync("api/PlanosManutencao/" + planoManutencao.ID, content);
            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return Content("Ocorreu um erro: " + response.StatusCode);
            }
        }
        catch
        {
            return Content("Ocorreu um erro.");
        }
    }

    // GET: PlanosManutencao/Delete/5
    public async Task<ActionResult> Delete(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao/" + id);
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var planoManutencao = JsonConvert.DeserializeObject<PlanoManutencaoViewModel>(content);
            if (planoManutencao == null) return HttpNotFound();
            return View(planoManutencao);
        }
        return Content("Ocorreu um erro: " + response.StatusCode);
    }

    // POST: PlanosManutencao/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> DeleteConfirmed(int id)
    {
        try
        {
            var client = WebApiHttpClient.GetClient();
            var response = await client.DeleteAsync("api/PlanosManutencao/" + id);
            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return Content("Ocorreu um erro: " + response.StatusCode);
            }
        }
        catch
        {
            return Content("Ocorreu um erro.");
        }
    }

    private void PopulateDropDownListForAtivos(object ativos = null)
    {
        IEnumerable<AtivoViewModel> vm = null;
        using (var client=WebApiHttpClient.GetClient())
        {
            HttpResponseMessage response = client.GetAsync("api/Ativos").Result;
            if(response.IsSuccessStatusCode)
            {
                vm = response.Content.ReadAsAsync<IEnumerable<AtivoViewModel>>().Result;
            }
        }
        var Ativos = vm.ToList().OrderBy(i => i.ID);
        ViewBag.Ativos = new SelectList(Ativos, "ID", "Nome");
    }

}



 public class AtivosController : Controller
{
    // GET: Ativos
    public async Task<ActionResult> Index()
    {
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/Ativos");
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var ativos =
            JsonConvert.DeserializeObject<IEnumerable<AtivoViewModel>>(content);
            return View(ativos);
        }
        else
        {
            return Content("Ocorreu um erro: " + response.StatusCode);
        }
    }

    // GET: Ativos/Details/5
    public async Task<ActionResult> Details(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/Ativos/" + id);
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var ativo = JsonConvert.DeserializeObject<AtivoViewModel>(content);
            if (ativo == null) return HttpNotFound();
            return View(ativo);
        }
        else
        {
            return Content("Ocorreu um erro: " + response.StatusCode);
        }
    }

    // GET: Ativos/Create
    public ActionResult Create()
    {
        return View();
    }
    // POST: Ativos/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 async Task<ActionResult> Create(AtivoViewModel ativo)
    {
        try
        {
            var client = WebApiHttpClient.GetClient();
            string ativoJSON = JsonConvert.SerializeObject(ativo);
            HttpContent content = new StringContent(ativoJSON, System.Text.Encoding.Unicode, "application/json");
            var response = await client.PostAsync("api/Ativos", content);
            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return Content("Ocorreu um erro: " + response.StatusCode);
            }
        }
        catch
        {
            return Content("Ocorreu um erro.");
        }
    }

    // GET: Ativos/Edit/5
    public async Task<ActionResult> Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/Ativos/" + id);
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var ativo = JsonConvert.DeserializeObject<AtivoViewModel>(content);
            if (ativo == null) return HttpNotFound();
            return View(ativo);
        }
        return Content("Ocorreu um erro: " + response.StatusCode);
    }

    // POST: Ativos/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 async Task<ActionResult> Edit(AtivoViewModel ativo)
    {
        try
        {
            var client = WebApiHttpClient.GetClient();
            string ativoJSON = JsonConvert.SerializeObject(ativo);
            HttpContent content = new StringContent(ativoJSON, System.Text.Encoding.Unicode, "application/json");
            var response =
            await client.PutAsync("api/Ativos/" + ativo.ID, content);
            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return Content("Ocorreu um erro: " + response.StatusCode);
            }
        }
        catch
        {
            return Content("Ocorreu um erro.");
        }
    }

    // GET: Ativos/Delete/5
    public async Task<ActionResult> Delete(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var client = WebApiHttpClient.GetClient();
        HttpResponseMessage response = await client.GetAsync("api/Ativos/" + id);
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var ativo = JsonConvert.DeserializeObject<AtivoViewModel>(content);
            if (ativo == null) return HttpNotFound();
            return View(ativo);
        }
        return Content("Ocorreu um erro: " + response.StatusCode);
    }

    // POST: Ativos/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> DeleteConfirmed(int id)
    {
        try
        {
            var client = WebApiHttpClient.GetClient();
            var response = await client.DeleteAsync("api/Ativos/" + id);
            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Index");
            }
            else
            {
                return Content("Ocorreu um erro: " + response.StatusCode);
            }
        }
        catch
        {
            return Content("Ocorreu um erro.");
        }
    }
}

I'll post only the Create view of PlanoManutencao, which is:

<div class="form-horizontal">
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(model => model.Nome, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Nome, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Nome, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Observacoes, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Observacoes, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Observacoes, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Permanente, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            <div class="checkbox">
                @Html.EditorFor(model => model.Permanente)
                @Html.ValidationMessageFor(model => model.Permanente, "", new { @class = "text-danger" })
            </div>
        </div>
    </div>

    <div class="form-group">
        <label class="control-label col-md-2" for="ativos">Assets</label>
        <div class="col-md-10">
            @Html.DropDownList("ativos",String.Empty)
            @Html.ValidationMessageFor(model => model.Ativos)
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.DataCriacao, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.DataCriacao, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.DataCriacao, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>

EntityFramework creates the join table in the WebAPI DB just fine, but when i create one PlanoManutencao with one Ativo it creates the PlanoManutencao but does not add anything to the join table. I reckon it my be a mistake i have in the repositories or controllers, but i cannot solve it. I also followed lots of tutorials, none of which seem to solve my problem. I'm sorry for the long explanation, and thank you in advance, only for reading such a text :)

Try doing this inside your PlanosManutencaoRepo :

public class PlanosManutencaoRepository : IPlanosManutencaoRepository
{
    public PlanoManutencao Create(PlanoManutencao planoManutencao)
    {
        foreach(var a in planoManutencao.Ativos)
        {
            context.Ativos.Attach(a);
        }
        context.PlanosManutencao.Add(planoManutencao);
        context.SaveChanges();
        return planoManutencao;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM