none
Persistir entidad con referencia a entidad existente (Entity Framework) RRS feed

  • Pregunta

  • Trato de realizar mi logica de negocio para persistir entidades nuevas en la base de dato usando Entity Framework.

    Mi problema viene cuando trata de persistir la referencia, que ya existe en la base de datos.

    Pongo el ejemplo: tengo una entidad Noticia con algunas propiedades como Titulo, Subtitulo, Pie, Resumen y relacionada con otra entidad MedioComunicacion. En Noticia hay una propiedad de Navegación hacia el MedioComunicacion. Para crear una instancia de Noticia utilizo simplemente new y luego asigno las propiedades, incluida la de navegación MedioComunicacion que obtengo mediante el SelectedItem de un ComboListBox que está enlazado a un List<MedioComunicacion>.

    Mi método Add de la logica de negocio es el siguiente;

    public void Add(Noticia _noticia)
            {
                using (RepositorioEntities ctx = new RepositorioEntities())
                {
                    ctx.AddToNoticia(_noticia);
                    ctx.SaveChanges();
                }
            }
    El problema me viene porque la llamada a AddToNoticia me genera la siguiente excepción:

    InvalidOperationException: "Varias instancias de IEntityChangeTracker no pueden hacer referencia a un objeto de entidad."

    Alguna ayuda?

    Gracias de antemano.
    domingo, 27 de septiembre de 2009 11:54

Respuestas

  • Me autorespondo después de investigar mas sobre el tema he encontrado un articulo interesante sobre "intríngulis" del Entity Framework.

    http://www.code-magazine.com/article.aspx?quickid=0907071&page=1

    En este articulo se trata el problema que mi lógica de negocio que tiene una solución aparentemente muy sencilla.

    Cuando se asigna una entidad que ya existe en base de datos lo unico que hay que hacer es asignar al objeto Reference correspondiente la EntityKey de la entidad recuperada de base de datos, pero fuera del uso de un contexto. No hay que crear una nueva EntityKey si no usar la existente.

    Bajo mi punto de vista esta forma de trabajar no se adapta bien al trabajo con objetos habitual que deberia hacerse con Entity Framework, pero por lo que he leido es debido a una decisión de diseño del propio framework. Dejo aqui mi código de ejemplo:

    NoticiaDataAccess noticiaDA = new NoticiaDataAccess();
    Noticia nueva = Noticia.CreateNoticia(FechaNoticia.Value, (int)ListaMediosComunicacion.SelectedValue,
    	noticiaDA.SiguienteNoticia((int)ListaMediosComunicacion.SelectedValue, FechaNoticia.Value),
             TituloNoticia.Text, SubtituloNoticia.Text, Resumen.Text);            
    nueva.MedioComunicacionReference.EntityKey = ((MedioComunicacion)ListaMediosComunicacion.SelectedItem).EntityKey;
    noticiaDA.Add(nueva);

    El método Add de NoticiaDataAccess:

    public void Add(Noticia newItem)
    {
            using (RepositorioEntities context = new RepositorioEntities())
                {                
                    context.AddObject("Noticia", newItem);
                    context.SaveChanges();
                }
    }
    martes, 29 de septiembre de 2009 19:38

Todas las respuestas

  • Hola te copio un fragmento del escrito de Zeeshan Hirani Contributions to Entity framework community

    Problem:

    You want to create an address entity and assign it to a customer without loading customer entity. On the web page that allows inserting address, the customerid is passed in the query string. You want to read that customerid and assign it to the address.

     

    Solution:

     

    Since Address has many to 1 association with Customer entity, EF will not expose the foreign key customerid on Address entity. There will be two navigation property on address entity; Customer and CustomerReference. Customer property is a pointer to a CLR reference that represents customer entity. By default the Customer navigation property would be null unless you call Load or Include on an object query. CustomerReference is a relationship entry inside of Object State Manager that relates a customer to an address. CustomerReference is of type EntityReference<Customer> which has a property EntityKey. To retrieve or assign a customerid to address entity, we need to set the entitykeyvalues for the entity key on CustomerReference.

    Code below shows an example of assigning customerid 2 to the new address being created.

    var db = new OneToManyEntities();
    var address = new Address { Address1 = "Oakumber st", City = "Dallas", State = "Tx", Zip = "76111" };
    address.CustomerReference.EntityKey = new EntityKey("OneToManyEntities.Customer","CustomerId",2);
    db.AddToAddresses(address);
    db.SaveChanges();
    Saludos

    Si la respuesta es correcta, marcala como correcta.
    Tambien puedes votar como util si te fue de ayuda
    DCE 5 ESTRELLAS PLATINO
    domingo, 27 de septiembre de 2009 20:34
  • Gracias por la respuesta. Es algo que ya había probado porque me pareció que aunque yo le asignara a la propiedad de navegación el objeto, no tenia la referencia en el objeto ...Reference.

    Pero el problema, y la excepción, sigue siendo la misma.

    Creo que es una operación bastante común y que no deberia tener una solución complicada, pero estoy perdido despues de leer y buscar mucho.
    domingo, 27 de septiembre de 2009 22:59
  • Me autorespondo después de investigar mas sobre el tema he encontrado un articulo interesante sobre "intríngulis" del Entity Framework.

    http://www.code-magazine.com/article.aspx?quickid=0907071&page=1

    En este articulo se trata el problema que mi lógica de negocio que tiene una solución aparentemente muy sencilla.

    Cuando se asigna una entidad que ya existe en base de datos lo unico que hay que hacer es asignar al objeto Reference correspondiente la EntityKey de la entidad recuperada de base de datos, pero fuera del uso de un contexto. No hay que crear una nueva EntityKey si no usar la existente.

    Bajo mi punto de vista esta forma de trabajar no se adapta bien al trabajo con objetos habitual que deberia hacerse con Entity Framework, pero por lo que he leido es debido a una decisión de diseño del propio framework. Dejo aqui mi código de ejemplo:

    NoticiaDataAccess noticiaDA = new NoticiaDataAccess();
    Noticia nueva = Noticia.CreateNoticia(FechaNoticia.Value, (int)ListaMediosComunicacion.SelectedValue,
    	noticiaDA.SiguienteNoticia((int)ListaMediosComunicacion.SelectedValue, FechaNoticia.Value),
             TituloNoticia.Text, SubtituloNoticia.Text, Resumen.Text);            
    nueva.MedioComunicacionReference.EntityKey = ((MedioComunicacion)ListaMediosComunicacion.SelectedItem).EntityKey;
    noticiaDA.Add(nueva);

    El método Add de NoticiaDataAccess:

    public void Add(Noticia newItem)
    {
            using (RepositorioEntities context = new RepositorioEntities())
                {                
                    context.AddObject("Noticia", newItem);
                    context.SaveChanges();
                }
    }
    martes, 29 de septiembre de 2009 19:38