Problem saving a change using Entity Framework

Asked

Viewed 1,003 times

8

I am trying to persist a change I make to a record but am getting this error:

System.Invalidoperationexception: 'A referential Integrity Constraint Violation occurred: The Property value(s) of 'Unidadedemedida.Undmedidaid' on one end of a Relationship do not match the Property value(s) of 'Product.Unidademedidaid' on the other end.'

I am using the Entity Framework with Fluent API. The Produto with UnidadeMedida is *:1.

I debugged where I assign the values I receive from my view

public ProdutoViewModel Atualizar(ProdutoViewModel produtoViewModel)
        {
            var categoriaSelecionada =
                _categoriaService.ObterPorId(produtoViewModel.CategoriaId);

            var subCategoriaSelecionada =
                _subCategoriaService.ObterPorId(produtoViewModel.SubCategoriaId);

            var unidadeMedidaSelecionada =
                _unidadeMedidaService.ObterPorId(produtoViewModel.UndidadeMedidaId);

            var produto = Mapper.Map<ProdutoViewModel, Produto>(produtoViewModel);

            produto.Categoria = categoriaSelecionada;
            produto.SubCategoria = subCategoriaSelecionada;
            produto.UnidadeMedida = unidadeMedidaSelecionada;           

            _produtoService.Atualizar(produto);

            return produtoViewModel;
        }

And I see that get the assignments correctly, but I see that when it arrives in this piece of code

public virtual TEntity Atualizar(TEntity obj)
        {
            var entry = Db.Entry(obj);
            DbSet.Attach(obj);
            entry.State = EntityState.Modified;
            SaveChanges();

            return obj;
        }

I see that a unit reference measure is void. I can’t imagine why...

My Class Product

using System;

namespace K.Domain.Entities
{
    public class Produto
    {
        public Guid ProdutoId { get; set; }
        public string Descricao { get; set; }
        //public DateTime? Validade { get; set; }
        //public string Lote { get; set; }
        public virtual Categoria Categoria { get; set; }
        public virtual SubCategoria SubCategoria { get; set; }
        public virtual UnidadeDeMedida UnidadeMedida { get; set; }
        public Guid CategoriaId { get; set; }
        public Guid SubCategoriaId { get; set; }
        public Guid UnidadeMedidaId { get; set; }
        //public virtual ICollection<Localizacao> Localizacao { get; set; }
        //public virtual UndAdministrativa UndAdministrativa { get; set; }
        //public DateTime DataCadastro { get; set; }
        //public bool IsMedicamento { get; set; }

        public Produto()
        {
            ProdutoId = Guid.NewGuid();            
        }

        //public bool IsValid
        //{
        //    get
        //    {
        //        return ResultadoValidacao.IsValid;
        //    }
        //}
    }
}

My class Productoviewmodel

using K.Domain.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace K.Application.ViewModels
{
    public class ProdutoViewModel
    {
        public ProdutoViewModel()
        {
            ProdutoId = Guid.NewGuid();
            Categorias = new List<CategoriaViewModel>();
            SubCategorias = new List<SubCategoriaViewModel>();
            UnidadeMedidas = new List<UnidadeDeMedidaViewModel>();
        }

        [Key]
        public Guid ProdutoId { get; set; }

        [Required(ErrorMessage = ("Preencha uma descrição."))]
        [MaxLength(120, ErrorMessage = ("Máximo {0} caracteres."))]
        [MinLength(1, ErrorMessage = ("Mínimo {0} caracteres."))]
        [DisplayName("Descrição")]
        public string Descricao { get; set; }

        public IEnumerable<CategoriaViewModel> Categorias { get; set; }
        public IEnumerable<SubCategoriaViewModel> SubCategorias { get; set; }
        public IEnumerable<UnidadeDeMedidaViewModel> UnidadeMedidas { get; set; }

        public Guid CategoriaId { get; set; }
        public Guid SubCategoriaId { get; set; }
        public Guid UndidadeMedidaId { get; set; }

        public virtual Categoria Categoria { get; set; }
        public virtual SubCategoria SubCategoria { get; set; }
        public virtual UnidadeDeMedida UnidadeMedida { get; set; }
    }
}

I will be very happy if someone solves and explain the pq of this error.

  • Check that your classes (Productoviewmodel and Product>) are exactly equal in property relations and the Product class is correct in the context class. Also check the relationship of tables, I believe that when trying to save the unit of measure Entity is not understanding the property Unidademedidaid and Undmedidaid. I hope I helped the idea.

  • Could put your Product and Product class?

  • Coming filled the productViewModel.Undidademedidaid?

  • @joaoeduardorf I saw that I get the correct values from the View, but when I get to the class that tries the Update and it gives that error that I reported upstairs.

4 answers

1

Turns out you’re filling out the property UnidadeMedida but not the UnidadeMedidaId.

Leave your code more or less like this:

public ProdutoViewModel Atualizar(ProdutoViewModel produtoViewModel)
{
    var categoriaSelecionada =
        _categoriaService.ObterPorId(produtoViewModel.CategoriaId);

    if(categoriaSelecionada == null)
    {//Alguma validação}

    var subCategoriaSelecionada =
        _subCategoriaService.ObterPorId(produtoViewModel.SubCategoriaId);

    if(subCategoriaSelecionada == null)
    {//Alguma validação}

    var unidadeMedidaSelecionada =
        _unidadeMedidaService.ObterPorId(produtoViewModel.UndidadeMedidaId);

    if(unidadeMedidaSelecionada == null)
    {//Alguma validação}

    var produto = Mapper.Map<ProdutoViewModel, Produto>(produtoViewModel);

    //Com o Mapper talvez não seja necessário essa etapa
    produto.CategoriaId = categoriaSelecionada.CategoriaId;
    produto.SubCategoriaId = subCategoriaSelecionada.SubCategoriaId;
    produto.UndidadeMedidaId = unidadeMedidaSelecionada.UndidadeMedidaId;           

    _produtoService.Atualizar(produto);

    return produtoViewModel;
}

If you fill in the object it may be that it tries to make a "cascade Insert", that is, it will "reinsert" the measured unit. Leave objects(Category, Subcategory and Unidademedida) null and fill only the ID.

  • Now that I’ve seen the Mapper, maybe you don’t even have to do the "manual assignment"

0

Your objects are probably generating conflict by Foreignkey because you have related three entities in this format:

Triangulo

If this is your case, changing the Foreign key of Object 2 will also mean changing Object 1 and Object 3.

:::Edit:::

Dude, it’s relationship error, you’re updating the Group and Subgroup, that is, the dependencies of the Unit of Measure, imagine the following:

I need to update the Group: Who depends on Group? The Subgroup and the Unit of Measurement. Okay, I’ll update the Group, Subgroup and Unit of Measurement.

I need to update the subgroup: Who depends on Subgroup? The Unit of Measure. Okay, I’ll update the Unit of Measurement.

And what you’re doing is more or less like this: Entity, I’ve updated the Subgroup. Update all other dependent tables. However, unfortunately, EF6 does not understand this when it performs an Update in this situation where there is a chain of dependencies.

Surely there must be more solutions than those I will mention, but at first you can either remove the dependency of Foreign Key or else specify the key of the Object and the Object itself that will be updated. I also believe it is possible to specify through the Fluent API itself, in the class where you do entity records.

For comparison purposes, this can be equated to a composite key.

Besides, I hope I helped you.

0

Maybe it works that way:

public virtual TEntity Atualizar(TEntity obj)
{

    Db.Entry<TEntity>(obj).State = EntityState.Modified;
    Db.SaveChanges();

    return obj;

}
  • I’ve tried that, but it doesn’t work... =(

0

First of all, by error message the problem may be na directly in the Measurement Unit Id. But I make three observations that you can consider:

1 - Note that you may be working with different connections. These 3 services below that seek related entities are using the same context created?

_categoriaService.ObterPorId(produtoViewModel.CategoriaId);
_subCategoriaService.ObterPorId(produtoViewModel.SubCategoriaId);
_unidadeMedidaService.ObterPorId(produtoViewModel.UndidadeMedidaId);

2 - For test level, try to search directly for the context and add directly for it, something like:

var categoriaSelecionada = context.Categoria.Find(produtoViewModel.CategoriaId);
var subCategoriaSelecionada = context.SubCategoria.Find(produtoViewModel.SuCategoriaId);
var unidadeMedidaSelecionada = context.UnidadeMedida.Find(produtoViewModel.UnidadeMedidaId);

3 - The second option would simply consider not assigning the related object and only the Ids:

produto.CategoriaId = categoriaSelecionada.Id;
produto.SubCategoriaId = subCategoriaSelecionada.Id;
produto.UnidadeMedidaId = unidadeMedidaSelecionada.Id;   

Note that in this environment Entity will try to update all entities related to the Product. Type, if you change the category name, the EF will save this change when doing the SaveChanges.

Browser other questions tagged

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