none
¿Por qué no se persisten los datos al editar una propiedad compleja de un objeto? RRS feed

  • Pregunta

  • Hola, les cuento que estoy trabajando con la última versión de EF y con sus controladores y vistas autogeneradas.

    Este es el código del método del controlador encargado de acualizar el objeto:

     

    [HttpPost]
        public ActionResult Edit(Producto producto, int[] AtributosSeleccionados)
        {
          ICollection<Atributo> Atributos = new List<Atributo>();
          foreach (var atributo in AtributosSeleccionados)
          {
            Atributo atributoSeleccionado = db.Atributo.Find(atributo);
            Atributos.Add(atributoSeleccionado);
          }
    
          producto.Atributos = Atributos;
    
    
          if (ModelState.IsValid)
          {
            db.Entry(producto).State= EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
          }
          else
          {
             //hacer otra cosa
          }
        }
    

    Cuando durante la depuración hago una ejecución paso a paso los valores están ahi, sin embargo, los mismos no se persisten. Sin embargo los atributos simples sí lo hacen. ¿Alguno sería tan amable de explicarme por qué puede estar produciéndose este comportamiento y/o cómo corregirlo?

    Gracias, saludos!

    Laura.-

     

    viernes, 20 de mayo de 2011 20:12

Todas las respuestas

  • Puedes probar adicionar los atributos directamente a la colección que tienes en producto?

    foreach (var atributo in AtributosSeleccionados)
    {
        Atributo atributoSeleccionado = db.Atributo.Find(atributo);
        producto.Atributos.Add(atributoSeleccionado);
    }

    No trabajo con EF pero casi todos los ORM siguen la mísma lógica.. se enteran que algo ha cambiado en la colección cuando manejas directamente los elementos que la contienen...

    Prueba y nos cuentas... ;)

    Salu2


    MCTS ADO.NET, MCTS WCF, MCTS WinForm, MCTS ASP.NET, MCPD Enterprise 3.5.

    Mi perfil: www.odelvalle.com
    Colaborador: www.secondnug.com
    sábado, 21 de mayo de 2011 7:00
    Moderador
  • Hola Omar, antes que nada gracias por contestar. Te comento que ya había probado ese enfoque también, pero tampoco lo persiste... Lo que me llama la atención es que ese comportamiento sólo se da en las propiedades que son colecciones, ya que las propiedades simples e incluso  las que se corresponden con otros objetos sí se actualizan.

    Es bastante desconcertante, la verdad... :S

    Saludos!

     

    Laura.-

    sábado, 21 de mayo de 2011 16:01
  • Tiene lógica que no pase con las propiedades simples... supuestamente cada propiedad "simple" está directamente relacionada a un campo de la tabla, mientras que una colección "casi siempre" representa una relación entre dos tablas.. 1 a N por ejemplo..

    Por casualidad no tendrías que modificar el estado también de cada uno de los atributos que insertas?

    Ej:

    foreach (var atributo in AtributosSeleccionados)
    {
        Atributo atributoSeleccionado = db.Atributo.Find(atributo);
        Atributos.Add(atributoSeleccionado);

        db.State(atributoSeleccionado).State= EntityState.Modified;
    }

    Seguimos probando... ;)


    MCTS ADO.NET, MCTS WCF, MCTS WinForm, MCTS ASP.NET, MCPD Enterprise 3.5.

    Mi perfil: www.odelvalle.com
    Colaborador: www.secondnug.com
    sábado, 21 de mayo de 2011 16:17
    Moderador
  • Mmmm... Parece que así tampoco :S

    Sin embargo elimininar la entidad antigua y crear una nueva entidad si funciona.... ¿Será que el binding que hace MVC tiene algo que ver con este comportamiento?

     

    sábado, 21 de mayo de 2011 17:42
  • También he intentado con

    UpdateModel(producto);
    db.SaveChanges();
    

    Donde db es el contexto, pero tampoco se persisten los cambios en las propiedades que son colecciones...

     

     

    sábado, 21 de mayo de 2011 21:34
  • Luego de renegar un par de horas conseguí que se persistan los cambios que realizo a la propiedad que alberga una colección. Sin embargo no termino de entender el por qué de este comportamiento. Por si a alguien más le sirve así es cómo quedó el código:

     

     

    [HttpPost]
      public ActionResult Edit(FormCollection collection, int[] AtributosSeleccionados, int ProductoId)
      {
       var producto = db.Producto.Find(ProductoId);
    
       ICollection<Atributo> Atributos = new List<Atributo>();
       foreach (var atributo in AtributosSeleccionados)
       {
        Atributo atributoSeleccionado = db.Atributo.Find(atributo);
        Atributos.Add(atributoSeleccionado);
       }
    
       producto.Atributos = Atributos;
    
    
       if (TryUpdateModel(producto))
       {
        db.SaveChanges();
        return RedirectToAction("Index");
       }
       else
       {
         //hacer otra cosa
       }
      }
    
    

     

     

    Cualquier explicación, aclaración u otro tipo de "desburramiento" será bienvenido :)

    Saludos!

     

    Laura.-

    sábado, 21 de mayo de 2011 22:50
  • que bien que ya te funciona ;)

    Me queda una duda.. me habias comentado que en tu código si modificabas una propiedad directa de producto sí te la actualizaba... ¿?

    De todas formas intento darte una explicación de lo que pasa...

    En todo ORM (linq2Sql, EF o NH que es el que uso) existe un contexto, para tu ejemplo sería "db". Ese contexto funciona como unidad de trabajo y su objetiivo es llevar el control de todo lo que pasa con las entidades, cual es nueva, cual se actualiza, cual se elimina, etc, etc.

    Existen varias maneras de manejar un contexto, uno de ellos es el Context per Request, esto significa que el contexto funciona por cada request que haces al servidor. El contexto se crea cuando se inicia el request y se destruye cuando este finaliza. Este debe ser tu caso...

    Cuando envias Producto desde el cliente, el contexto no conoce nada sobre esa entidad, por eso cualquier modificación que hagas a esta entidad (incluyendo a sus relaciones - atributos) no se persisten a la base de datos. Al hacer un Find de producto en ese request, ya el contexto sabe quien es producto y puede saber cualquier modificación que se haga sobre la entidad o sus relaciones. Por esto mismo si creabas una entidad nueva de producto también te funcionaba.

    La otra forma de manejar el contexto (fue la que pensé que usabas) es el LongConversation.. esto significa que el contexto persiste entre distintos Request y las modificaciones realizadas a una entidad en un Request son conocidas por el contexto en otro Request...

    La duda que te pregunto al principio viene precisamente por eso.. si en realidad lo que estás usando es Context per Request.. entonces en tu ejemplo inicial si modificas una propiedad "simple" de producto e intentas actualizar ese cambio, el contexto tampoco debería guardarla en BD...

    Salu2
    Omar

     


    MCTS ADO.NET, MCTS WCF, MCTS WinForm, MCTS ASP.NET, MCPD Enterprise 3.5.

    Mi perfil: www.odelvalle.com
    Colaborador: www.secondnug.com
    domingo, 22 de mayo de 2011 7:01
    Moderador
  • Hola Omar, te cuento que estoy usando el primer enfoque que comentas, el de un contexto por request, y efectivamente llamo "db" a ese contexto. Lo que me sigue desconcertando es que de la forma en lo guardaba los cambios en el primer código que posteé, si persistía los cambios, aunque sólo de propiedades que no fueran colecciones de objetos complejos. Pero si hacía un cambio a una propiedad que era un objeto complejo (por ejemplo tenía una propiedad "TipoProducto", donde TipoProducto es también otra clase), los cambios si se persitían.

    Sigo creyendo que ese compotamiento se debe a la forma en que funciona el binding automático, ya que cómo se vé en el último trozo de código que posteé, salvo para la colección de objetos nunca le digo explícitamente al contexto que otras propiedades cambiaron, y éste sin embargo las bindea solo desde el FormCollection y las persiste al darle save.

    Tengo esa sensación como de que se me está escapando la tortuga con esto... Y no veo por donde se va :P

    Saludos!

     

    Laura.-

     

    domingo, 22 de mayo de 2011 20:43