How to insert an existing record into the Entity Framework?

Asked

Viewed 525 times

2

At some point in the system some records are selected and should be replicated by changing only one value.

At this point I am selecting the records I need to enter:

listaRegistros = listaRegistros .GroupBy(r => r.Id)
                        .Select(grp => grp.First()).ToList();

Soon after I use these selected records above to insert new records in the table:

foreach (var orgao in listaOrgaosASeremAdicionados)
{
    foreach (var registro in listaRegistros)
        registro.Orgao = orgao;
    new RegistrosMeService().InsertListaRegistrosMe(listaRegistros);
}

Here is the InsertListaRegistrosMe class RegistrosMeService:

protected EFSpecificRepository<TB_RegistrosMe, Entities> _repository;
protected EFSpecificRepository<TB_RegistrosMe, Entities> Repository
{
    get
    {
        if (_repository == null)
            _repository = new EFSpecificRepository<TB_RegistrosMe, Entities>();
        return _repository;
    }
}

public int InsertListaRegistrosMe(List<TB_RegistrosMe> listaMe)
{
    Repository.InsertList(listaMe);
    Repository.SaveChanges();
}

The first loop, where the insertion is made, it is to inform to how many organs the list of records will be added, more than one may have been selected.

The only change made in the record is the one that can be verified in the loop, which is the amendment of registro.Orgao.

The problem is that in Insert the error occurs:

"There is already an object with the same key in Objectstatemanager. The object is in the Unchanged state. An object can only be added again to Objectstatemanager if it is in the added state."

I have tried to change Id, but while trying to do this also an error occurs:

'Id' property is part of the object’s key information and not can be modified.

From what I understand this problem occurs because I am observing a record that already exists in EF and for security it does not allow me to add this record because it considers it duplicated, correct?

But how could I solve this without creating a new object in EF 3.5 (v1)? It is possible to change the ObjectStateManager so that he can do the insertion?

  • @jbueno, I checked for my System.Data.Entity and that’s the same version. Another strange fact if it really doesn’t exist is tag be here at Sopt, but really when I search for this version I find nothing concrete about it. But I found here

  • What’s in RegistrosMeService.InsertListaRegistrosMe?

  • @Romaniomorrisonmendez is where are all methods of select, Insert, saveChanges. Want I edit with the method InsertListaRegistrosMe?

  • Yes, please. That’s the problem.

  • @Ciganomorrisonmendez I added the pegunta.

  • Another thing: there is no EF3.5. The first stable EF is 4.1, which should be what you are using.

  • @Ciganomorrisonmendez then version check by System.Data.Entity is not correct? How do I identify the version correctly?

  • Library EntityFramework, in your References, or version of the file packages.config.

Show 3 more comments

3 answers

3

The Entity Framework works with observable collections, that is, the records that are returned from your query are being "observed" by the context so that when (and if) there are changes these can be reflected in the database.

Use the method AsNoTracking() must resolve. This method "warns" the context that it is not necessary to observe changes in entities.

listaRegistros = listaRegistros.GroupBy(r => r.Id)
                    .Select(grp => grp.First()).AsNoTracking().ToList();
  • 1

    It doesn’t work. It seems that AsNoTracking() nor existed in that version. :(

  • Yeah, I didn’t stop to think about it. See if you do context.Configuration.AutoDetectChangesEnabled = false; helps you. This should have the same effect.

  • 1

    Nothing Configuration in context also, omg! To understand why you don’t find anything of EF 3.5, no one should use!

3

You have two alternatives.

Healthy alternative: clone the objects you want to copy and save the clones. The advantage is that whoever reads your code for maintenance will understand that it was clearly your intention to have new objects. I say this because reading the code you posted without considering the context of the question, I would swear on my feet, for my soul and for my mother, that you confused the terms Insert and update and that their intention was actually to edit existing records in the database instead of inserting new ones.

When inserting a completely new object into the repository, it is marked as a new object in the internal EF collections. When context is saved the new objects will be inserted into the database.

Mcgyver way: this way is very ugly. Seriously. If you do this on purpose I will find out who you are just to ensure that I will never shake your hand. I’m going to add this shape here for educational reasons, because a lot of people do this unintentionally when you start working with Entity Framework together with ASP.NET.

Simply load the objects in a context. Close the context. Now open another context, add the objects and save. The new context will understand that the objects are new (as it did not observe them during their retrieval) and will mark them all for creation in the database.

Most people when starting with ASP.NET don’t realize that you have a different context with each page request. People load objects in a GET request and change them in the processing of a POST request. This has already led to pages and pages of questions and answers in the Stack Overflow on object duplication when using Entity Framework. For most people this is a defect, but it seems that in your case it may be a Feature (depending on the life cycle of their objects).

  • 1

    Renan, I’m already doing the object clone, but I was wondering if it was possible to do something like the AsNoTracking() suggested by @jbueno. But by the way it’s not possible. I hope I can shake my hand one day if the opportunity arises!! hahah :D

3


If the record needs to be replicated, i.e., reinserted, you cannot reinsert with the same primary key value. You need to create new objects from objects that already exist. That is:

var novaListaDeRegistros = new List<Registro>();

foreach (var orgao in listaOrgaosASeremAdicionados)
{
    foreach (var registro in listaRegistros) 
    {
        novaListaDeRegistros.Add(new Registro 
        {
            // Coloque aqui todas as propriedades de Registro, 
            // com exceção do RegistroId, que será novo.
            registro.Orgao = orgao;
        });
    }
}

new RegistrosMeService().InsertListaRegistrosMe(novaListaDeRegistros);

PS: Get rid of that repository.

  • 2

    Gypsy, it was already working exactly the way you suggested, but I thought I could avoid it. As you suggested, the only way to avoid it will be to get rid of this repository.

Browser other questions tagged

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