c # Nhibernate a different object with the same identifier value was already associated with the session

4

I'm at a time with this error and can not find a good solution.

The recording of the objects works normally, however for changes it returns me this message:

  

Additional information: a different object with the same identifier   value was already associated with the session

Class returning to session

public class DataAccesLayer {
    private static DataAccesLayer _instance;
    public string ConnectionString { get; set; }

    private DataAccesLayer() {
    }

    private ISessionFactory _sessionFactory;

    private ISessionFactory SessionFactory {
        get {
            return _sessionFactory ?? (_sessionFactory = BuildFactory());
        }
    }

    public static DataAccesLayer Instance {
        get {
            return _instance ?? (_instance = new DataAccesLayer());
        }
    }

    private ISessionFactory BuildFactory() {
        try {
            IPersistenceConfigurer configDB = PostgreSQLConfiguration
                    .PostgreSQL82
                    .ConnectionString(ConnectionString)
                    .ShowSql()
                    .FormatSql()
                    .UseReflectionOptimizer();

            FluentConfiguration FConf = Fluently.Configure()
                .Database(configDB)
                .Mappings(c => c.FluentMappings.AddFromAssemblyOf<System.Retaguarda.Map.UsuarioMap>())
                .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true));

            return FConf.BuildSessionFactory();
        } catch (Exception ex) {
            Console.WriteLine("Erro ao carregar configurações do banco de dados\nDica: Verifique as configurações de conexão\n" + ex.Message + "\n" + ex.InnerException);
            throw ex;
        }
    }

    public ISession OpenSession() {
        return SessionFactory.OpenSession();
    }
}

Save Method

    ISession session = DataAccesLayer.Instance.OpenSession();

    public void Gravar(T entidade) {
        using (ITransaction transacao = session.BeginTransaction()) {
            try {
                session.SaveOrUpdate(entidade);
                transacao.Commit();
                session.Flush();
            } catch (Exception ex) {
                if (!transacao.WasCommitted) {
                    transacao.Rollback();
                }
                Console.WriteLine("Erro ao gravar:\n" + ex.Message + "\n" + ex.InnerException);
                throw ex;
            }
        }
    }

If you use session.Merge(entidade); it normally writes the changes, but the problem when inserting new items. I thought of a possible solution, but it was kind of strange and I do not intend to use it:

    try {
        session.SaveOrUpdate(entidade);
    } catch (Exception) {
        session.Merge(entidade);
    }

Another possibility that I tried was to execute a session.Clear(); before SaveOrUpdate , but when trying to save a "Person" object with "Address" list it returns another error:

  

Additional information: Illegal attempt to associate with collection with   two open sessions

    
asked by anonymous 16.12.2016 / 18:07

1 answer

3

Note that SaveOrUpdate() should only be used under one of these circumstances:

  • The object (entity) is new - ie, primary key is empty (zeroed, null, etc) and must be generated; It is equivalent to calling the method Save() ;
  • The object (entity) has a key that already exists in the database , but has not yet been loaded by ISession . It is equivalent to calling the method Update() ;

The Merge() method does the same procedure above by adding the following behavior:

  • If the entity has a valid primary key, it reads the record to see if it exists in the database (equivalent Get() ). If it already exists, it copies the data from the updated entity to the newly loaded entity of the database. If it does not exist, consider Save() ;

If, however, an entity is already loaded in the session cache (via method Get() or lazy-load , for example), any of the above methods will fail.

When an entity is already loaded in ISession , it is not necessary to call any method to effect the change. This is because NHibernate is a framework that has native change-tracking .

In your case, the update should be summarized simply like this:

// só isto basta - note que isto irá atualizar (UPDATE) 
// todas as entidades cujas propriedades foram alteradas
session.Flush();
    
16.12.2016 / 19:17