4
I’ve been with that mistake for a while and I can’t find a good solution.
Saving objects works normally, but for changes it returns me this message:
Additional information: a Different Object with the same Identifier value was already Associated with the Session
Class that returns 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 saves the changes, but of the problem when inserting new items. I thought of a possible solution, but it got a little strange and I don’t intend to use:
try {
session.SaveOrUpdate(entidade);
} catch (Exception) {
session.Merge(entidade);
}
Another possibility I tested was running a session.Clear();
before the SaveOrUpdate
, but trying to save a "Person" object with "Address" list returns another error:
Additional information: Illegal Attempt to Associate a Collection with two open Sessions
Interesting explanation, makes perfect sense. But in this way it is changing only in Session, while I have it open (it does not record in the database). What could I be doing wrong?
– ebitencourt
The
session.Flush()
should in itself fire the(s)UPDATE
(s) and any other database change commands. Another way would be to use theISession
within a blockusing
(similar as you did with the transaction), which is recommended by the concept that Nhibernate is based on (Unit-of-work Pattern), triggering all changes made to the database at the end of theusing
.– Jônatas Hudler
Just another detail. As the Nhibernate observes its entities (once they have been loaded), it will only fire one
UPDATE
if a (at least) property has been changed. Entities that have not been changed do not generate any DML command toFlush()
.– Jônatas Hudler
So in the research I found something in this sense:
O objeto SessionFactory, este sim deve ser criado apenas uma vez e único por banco de dados. (SessionFactory = singleton)
O objeto Session tem um custo muito pequeno de criação, e deve ser criado / destruído a cada ciclo (OpenSession())
. This way I have a Session for each transaction:using (ISession session = DataAccesLayer.Instance.OpenSession()) {...}
– ebitencourt
In that case the:
session.SaveOrUpdate(entidade);
works perfectly for all objects. But when trying to load the person object with a list of addresses, it brings only the person and the error when trying to access the address:-failed to lazily initialize a collection of role: Pessoa.Enderecos, no session or session was closed
&#Then I realized that if I use .Not.Lazyload() in the attribute Addresses within the Personal Map, it loads normal. It would be correct to use this way, or lose much in performance?– ebitencourt