Good morning,
I'm having trouble updating a record with entityframework, I'll tell you the whole structure below. In short, I have a register of artists, where these artists are related to address and categories.
An artist can have an address (one for one), and artists can have many categories (many for many).
entities:
Artist: one-to-one relationship with address many-to-many relationship with categories
public class Artista
{
public Artista()
{
ArtistaCategoria = new List<ArtistaCategoria>();
}
public int ArtistaId { get; set; }
public string Nome { get; set; }
public string Email { get; set; }
public string Site { get; set; }
public string Descricao { get; set; }
public virtual Endereco Endereco { get; set; }
public DateTime DataCadastro { get; set; }
public DateTime DataAtualizacao { get; set; }
public virtual ICollection<ArtistaCategoria> ArtistaCategoria { get; set; }
}
public class Categoria
{
public Categoria()
{
}
public int CategoriaId { get; set; }
public string Nome { get; set; }
public virtual ICollection<ArtistaCategoria> ArtistaCategoria { get; set; }
}
public class Endereco
{
public Endereco()
{
Municipio = new Municipio();
}
public int EnderecoId { get; set; }
public string Logradouro { get; set; }
public string Numero { get; set; }
public string Bairro { get; set; }
public string Cep { get; set; }
public int MunicipioId { get; set; }
public virtual Municipio Municipio { get; set; }
}
public class Municipio
{
public Municipio()
{
}
public int MunicipioId { get; set; }
public string Nome { get; set; }
public string Cep { get; set; }
}
Fluent API Configuration
public class ArtistaConfiguration : EntityTypeConfiguration<Artista>
{
public ArtistaConfiguration()
{
HasKey(a => a.ArtistaId);
Property(a => a.Nome)
.IsRequired();
Property(a => a.Email)
.HasMaxLength(150);
}
public class EnderecoConfiguration : EntityTypeConfiguration<Endereco>
{
public EnderecoConfiguration()
{
HasKey(x => x.EnderecoId);
Property(x => x.Logradouro).IsRequired();
HasRequired(m => m.Municipio)
.WithMany()
.HasForeignKey(m => m.MunicipioId);
Property(m => m.Cep)
.IsFixedLength()
.HasMaxLength(9)
.HasColumnType("char");
}
}
I am not able to edit the data, when I save the categories, an error is shown stating that the MunicipalityId is invalid.
I have always worked with ADO and Stored Procedures, and I have always heard a lot of people say that this is an oversight, that with Entity is much faster and easier, but honestly I think I lost control, with SPs you have the application in hand , any error is easy to identify.
In this case, when editing the relationship of the category and the artist, an error is generated in the municipality (artist > address> municipality), I honestly can not identify the problem.
Follow the update code:
public void Update(Artista obj, string[] arrayCategoria)
{
AtualizaEndereco(obj);
ValidaCategorias(obj, arrayCategoria);
Db.Entry(obj).State = EntityState.Modified;
Db.SaveChanges();
}
private void AtualizaEndereco(Artista artista)
{
var endereco = artista.Endereco;
endereco.Municipio = null;
Db.Entry(endereco).State = EntityState.Modified;
}
private void AtualizarCategorias(Artista artista, string[] categorias)
{
var artistaAtual = Db.Artistas
.FirstOrDefault(a => a.ArtistaId == artista.ArtistaId);
//todo: fazer lista de categoria de acordo com array recebido
List<Categoria> categoriasSelecionadas = new List<Categoria>();
if (categorias != null)
{
foreach (var cat in categorias)
{
categoriasSelecionadas.Add(Db.Categorias.Find(int.Parse(cat)));
}
}
foreach (var categoria in categoriasSelecionadas)
{
var artistaCategoria = new ArtistaCategoria
{
Artista = artistaAtual,
Categoria = categoria
};
Db.ArtistaCategoria.Add(artistaCategoria);
Db.SaveChanges();
}
}
Controller code that edits the registry:
public class ArtistaController : Controller
{
private readonly IArtistaAppService _artistaApp;
private readonly IMunicipioAppService _municipioApp;
private readonly ICategoriaAppService _categoriaApp;
public ArtistaController(IArtistaAppService artistaApp, IMunicipioAppService municipioApp, ICategoriaAppService categoriaApp)
{
_artistaApp = artistaApp;
_municipioApp = municipioApp;
_categoriaApp = categoriaApp;
}
[...]
[HttpPost]
[ValidateInput(false)]
public ActionResult Edit(ArtistaViewModel artista, string[] arrayCategoria)
{
if (ModelState.IsValid)
{
var artistaDomain = Mapper.Map<ArtistaViewModel, Artista>(artista);
_artistaApp.Update(artistaDomain, arrayCategoria);
return RedirectToAction("index");
}
return View(artista);
}
@model ViewModels.ArtistaViewModel
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default" data-collapsed="0">
<div class="panel-heading">
<div class="panel-title">
Dados do cadastro<br />
</div>
<div class="panel-options">
<a href="#" data-rel="collapse"><i class="entypo-down-open"></i></a>
</div>
</div>
<div class="panel-body">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.ArtistaId)
<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.Email, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button class="btn btn-blue btn-icon" type="button" id='addButton'>Adicionar telefone<i class="entypo-phone"></i></button>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Endereco.Cep, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
@Html.EditorFor(model => model.Endereco.Cep, new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Endereco.Logradouro, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
@Html.EditorFor(model => model.Endereco.Logradouro, new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Endereco.Numero, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
@Html.EditorFor(model => model.Endereco.Numero, new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Endereco.Bairro, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
@Html.EditorFor(model => model.Endereco.Bairro, new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Endereco.MunicipioId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-5">
<select id="Endereco_MunicipioId" name="Endereco.MunicipioId" class="form-control"></select>
</div>
</div>
@Html.HiddenFor(model => model.Endereco.EnderecoId)
@{
List<ViewModels.CategoriasSelecionadas> categorias = ViewBag.Categorias;
foreach (var categoria in categorias)
{
<input type="checkbox"
name="arrayCategoria"
value="@categoria.CategoriaId"
@(Html.Raw(categoria.Selecionada ? "checked=\"checked\"" : "")) />
@categoria.CategoriaId @: @categoria.Nome
}
}
</div>
</div>
</div>
</div>
</div>
<div class="form-group default-padding">
<button class="btn btn-success btn-icon" type="submit">Salvar<i class="entypo-check"></i></button>
<button type="reset" class="btn btn-icon btn-default">Cancelar alterações <i class="entypo-cancel"></i></button>
<a href="@Url.Action("Index")" class="btn btn-icon btn-info">Voltar para listagem<i class="entypo-reply"></i></a>
</div>
}