Error saving list of MVC C#objects

Asked

Viewed 1,005 times

1

As the post Edit object list with POST form in MVC C# I was able to make my application display the values. However, trying to save the data gives the error:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

In Portuguese, for documentation:

Falha na operação: a relação não pôde ser alterada porque uma ou mais propriedades da chave estrangeira não é nula. Quando uma alteração é feita em uma relação, a propriedade relacionada da chave estrangeira é definida como um valor nulo. Se a chave estrangeira não der suporte a valores nulos, uma nova relação deverá ser definida, a propriedade da chave estrangeira deverá ser atribuída a outro valor não nulo ou o objeto não relacionado deverá ser excluído.

This is my implementation:

Model

public class ProdutoPadrao : IEntidadeBase
{
  [Key]
  public int ProdutoPadraoID { get; set; }
  [Display(Name = "Descrição")]
  public string Descricao { get; set; }
  [Display(Name = "Detalhe")]
  public string Detalhe { get; set; } 
  public virtual ICollection<ProdutoPadraoCaracteristica> ListaProdutoCaracteristica { get; set; }    
}

public class ProdutoPadraoCaracteristica : IEntidadeBase
{
  [Key]
  public int ProdutoPadraoCaracteristicaID { get; set; }
  public int ProdutoPadraoID { get; set; }
  public string Descricao { get; set; }
  public int TipoCaracteristicaID { get; set; }    
  [ForeignKey("ProdutoPadraoID")]
  public virtual ProdutoPadrao ProdutoPadrao { get; set; }
}    

Controller GET

[ControleDeAcesso(TipoAcao.Normal)]
[Authorize]
public ActionResult Detalhar(int id)
{
    using (var db = new ERPContext())
    {
        var produtoPadrao = db.ProdutoPadrao.Include("ListaProdutoCaracteristica").Where(w => w.ProdutoPadraoID == id).ToList().FirstOrDefault();
        var retorno = EntidadeBaseExt.ValidarRegistro(produtoPadrao, TipoAcao.Visualizar);
        if (retorno != "")
        {
            TempData["MsgRetornoError"] = retorno;
            return RedirectToAction("Index", "Home");
        }
        ViewBag.ListaCaracteristica = new SelectList(ListagemPadrao.ListaTipoCaracteristica(), "Key", "Texto");
        ViewBag.ListaUnidadeMedida = new SelectList(db.UnidadeMedida.ToListERP().Select(l => new ItemLPesquisa { Key = l.UnidadeMedidaID, Texto = l.Descricao }).ToArray(), "Key", "Texto");
        return View(produtoPadrao);
    }
}

Controller POST

[Authorize]
[HttpPost]
[ControleDeAcesso(TipoAcao.Normal)]
public ActionResult Detalhar(string btnSubmit, ProdutoPadrao model)
{
    if (!ModelState.IsValid)
    {                
        return View(model);
    }

    using (var db = new ERPContext())
    {
        var produtoPadrao = db.ProdutoPadrao.Include("ListaProdutoCaracteristica").Where(w => w.ProdutoPadraoID == model.ProdutoPadraoID).ToList().FirstOrDefault();
        var retorno = FlexGestor.Helpers.EntidadeBaseExt.ValidarRegistro(produtoPadrao, TipoAcao.Gravar);
        if (retorno != "")
        {
            TempData["MsgRetornoError"] = retorno;
            return RedirectToAction("Index", "Home");
        }
        model.ListaProdutoCaracteristica = null;
        if (btnSubmit != "Excluir")                
            UpdateModel(produtoPadrao);

        FlexGestor.Helpers.EntidadeBaseExt.AtribuirValores(produtoPadrao, btnSubmit);
        db.Entry(produtoPadrao).State = EntityState.Modified;
        db.SaveChanges();

        if (btnSubmit == "Excluir")
            return RedirectToAction("Index", controller);

        return RedirectToAction("Detalhar", controller, new { id = model.ProdutoPadraoID });
    }
}

View Principal

@model FlexGestor.Models.ProdutoPadrao


@using (Html.BeginForm())
{
    <div class="row">                
        @Html.TituloPagina("Visualizando Produto Padrão", "Clique para abrir a ajuda", "#help_produtoPadrao")
        @Html.HiddenFor(m => m.ProdutoPadraoID)
        <div class="col-md-12">
            @Html.LabelFor(m => m.Descricao) @Html.ValidationMessageFor(m => m.Descricao)
            @Html.TextBoxFor(m => m.Descricao, new { @class = "form-control" })
        </div>
        <div class="col-md-12">
            @Html.LabelFor(m => m.Detalhe) @Html.ValidationMessageFor(m => m.Detalhe)
            @Html.TextAreaFor(m => m.Detalhe, new { @class = "form-control", @rows = "4" })
        </div>

    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.ListaProdutoCaracteristica)
        <div class="controls">
            <ul id="PhonesEditor" style="list-style-type: none">
                @if (Model.ListaProdutoCaracteristica != null)
                {
                    foreach (var item in Model.ListaProdutoCaracteristica)
                    {
                        Html.RenderPartial("_CustomerPhonesEditor", item);
                    }
                }
            </ul>
        </div>
        <p><a id="addAnother" class="small-button">AddPhone</a></p>
    </div>

    <div class="row">        
        <div class="col-md-12">
            @Html.BotaoTelaDetalhar()
        </div>
    </div>
}

View Detail

@model FlexGestor.Models.ProdutoPadraoCaracteristica


@using (Html.BeginCollectionItem("ListaProdutoCaracteristica"))
{
    @Html.HiddenFor(m => m.ProdutoPadraoID)
    @Html.HiddenFor(m => m.ProdutoPadraoCaracteristicaID)

    <div class="col-md-3">
        @Html.LabelFor(m => m.TipoCaracteristicaID) @Html.ValidationMessageFor(m => m.TipoCaracteristicaID)
        @Html.DropDownList("TipoCaracteristicaID", (SelectList)ViewBag.ListaCaracteristica, String.Empty,
                      new { @class = "form-control" })
    </div>

    <div class="col-md-9">
        @Html.LabelFor(m => m.Descricao) @Html.ValidationMessageFor(m => m.Descricao)
        @Html.TextBoxFor(m => m.Descricao, new { @class = "form-control" })
    </div>

    <div class="form-group">
        <div class="controls">
            <a onclick="$(this).parent().parent().parent().remove();" class="small-button" style="float: left;">Delete</a>
        </div>
    </div>
}
  • 1

    Just clarify one thing: in which line of these sources is the error?

  • @Gypsy omorrisonmendez sorry, I forgot to say... On this line db.SaveChanges();

  • What does this function? UpdateModel()

  • He takes the data from model and arrow the values in the object. If I’m not mistaken, it’s . Net or Entity Framework.

  • Can you please put it in the question?

  • @Gypsy I checked and she’s from class System.Web.Mvc. I think the problem is because I am using MVC 4 and EF 4. It will be if I upgrade it might be that it works?

  • I don’t think that’s it. I think the method UpdateModel() changes something that should not.

  • @Ciganomorrisonmendez what I find funny is if there is nothing on the list, it saves right. ? However if you have a record already on ListaProdutoCaracteristica gives the error. I’ll see if I can find some way to take the record the son records.

Show 3 more comments

1 answer

1

Hello Marlon by what it seems to me when you mark the object with state modified, EF understands that all its fields have been modified, and since there is a relationship between the models, ends up generating the error. I believe that defining this relationship as "Scade" can solve the problem, or maybe you can try to make the changes this way:

ProdutoPadrao.Campo1 = "Valor 1";
ProdutoPadrao.Campo2 = "Valor 2";
context.ListProdutoPadrao.Attach(ProdutoPadrao);
context.Entry(ProdutoPadrao).Property(p => p.Campo1).IsModified = true;
context.Entry(ProdutoPadrao).Property(p => p.Campo2).IsModified = true;

The form I quoted above will not put the "modified" state in your Foreign-key, so EF will most likely not accuse the error.

Note: I don’t know the name of your Dbset in its context, so I named it "Listproductopadrao"

Browser other questions tagged

You are not signed in. Login or sign up in order to post.