web-dev-qa-db-fra.com

nhibernate: un objet différent avec le même identifiant a déjà été associé à la session: 2, de l'entité:

Je reçois l'erreur suivante lorsque j'ai essayé de sauvegarder mon entité "Société" dans mon application MVC.

un objet différent avec le même identifiant a déjà été associé à la session: 2, de l'entité:

J'utilise un conteneur IOC

private class EStoreDependencies : NinjectModule
    {
        public override void Load()
        {

            Bind<ICompanyRepository>().To<CompanyRepository>().WithConstructorArgument("session",
                                                                                       NHibernateHelper.OpenSession());
        }
    }

Mon dépôt d'entreprise

public class CompanyRepository : ICompanyRepository
{
    private ISession _session;

    public CompanyRepository(ISession session)
    {
        _session = session;
    }    

    public void Update(Company company)
    {

        using (ITransaction transaction = _session.BeginTransaction())
        {

            _session.Update(company);
            transaction.Commit();
        }
    }

}

Et assistant de session

public class NHibernateHelper
{
    private static ISessionFactory _sessionFactory; 
    const string SessionKey = "MySession";


    private static ISessionFactory SessionFactory
    {
        get
        {
            if (_sessionFactory == null)
            {
                var configuration = new Configuration();
                configuration.Configure();
                configuration.AddAssembly(typeof(UserProfile).Assembly);
                configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName,
                                          System.Environment.MachineName);
                _sessionFactory = configuration.BuildSessionFactory();
            }
            return _sessionFactory;
        }
    }

    public static ISession OpenSession()
    {
        var context = HttpContext.Current;
        //.GetCurrentSession()

        if (context != null && context.Items.Contains(SessionKey))
        {
            //Return already open ISession
            return (ISession)context.Items[SessionKey];
        }
        else
        {
            //Create new ISession and store in HttpContext
            var newSession = SessionFactory.OpenSession();
            if (context != null)
                context.Items[SessionKey] = newSession;

            return newSession;
        }
    }
}

Mon action MVC

    [HttpPost]
    public ActionResult Edit(EStore.Domain.Model.Company company)
    {

            if (company.Id > 0)
            {

                _companyRepository.Update(company);
                _statusResponses.Add(StatusResponseHelper.Create(Constants
                    .RecordUpdated(), StatusResponseLookup.Success));
            }
            else
            {
                company.CreatedByUserId = currentUserId;
               _companyRepository.Add(company);
            }


        var viewModel = EditViewModel(company.Id, _statusResponses);
        return View("Edit", viewModel);
    }
23
frosty

Je sais que c'est un peu tard et que vous avez peut-être déjà trouvé la solution, mais que d'autres en bénéficieraient peut-être ...

Cette erreur est générée par nHibernate lorsque vous mettez à jour une instance d'une entité enregistrée dans le cache. En gros, nHibernate stocke vos objets dans le cache une fois que vous l’avez chargé. Ainsi, les prochains appels seront récupérés à partir du cache. Si vous mettez à jour une instance présente sur le cache, nHibernate lève cette erreur, sinon cela pourrait entraîner des lectures altérées et des conflits concernant le chargement de l'ancienne copie de l'objet. Pour résoudre ce problème, vous devez supprimer l'objet du cache à l'aide de la méthode Evict, telle que:

public ActionResult Edit(EStore.Domain.Model.Company company) 
{ 

        if (company.Id > 0) 
        { 
            **ISession.Evict(company);**
            _companyRepository.Update(company);

J'espère que cela t'aides.

37
Claiton Lovato

J'ai essayé le bidouillage de @ claitonlovatojr, mais je ne pouvais toujours pas gérer l'erreur.

Tout ce que je devais faire dans mon cas était de remplacer mon appel ISession.Update(obj) à ISession.Merge(obj).

Dans votre référentiel, changez:

public void Update(Company company)
{
    using (ITransaction transaction = _session.BeginTransaction())
    {
        //_session.Update(company);
        _session.Merge(company); // <-- this
        transaction.Commit();
    }
}

En outre, pour plus d'informations, voir cette réponse .

10
Joel

Une solution possible consiste à lire l'objet dans la base de données, à copier les champs dans l'objet et à le sauvegarder. La session NHibernate ne sait rien de l'objet entrant qui a été instancié par un classeur de modèle MVC. 

Dans certains cas, l'objet complet peut ne pas être visible ou transmis à View/ViewModel. Lors de la sauvegarde, commencez par lire NHibernate, puis mettez à jour et sauvegardez.

Company cOrig = _companyRepository.Get(company.Id);
cOrig.PropertyToUpdate = company.PropertyToUpdate;
... // Copy the properties to be updated.
// Save the freshly retrieved object! 
// Not the new object coming from the View which NHibernate Session knows nothing about.
_companyRepository.Update(cOrig);

Cela nécessite d’analyser/de mapper les propriétés ViewModel/Class sur le modèle/classe de domaine, mais dans la plupart des cas, vous ne les présentez pas nécessairement pour toutes les mettre à jour dans la vue. objets au-dessus d'objets anciens).

4
lko

pour une manière plus agressive, vous pouvez utiliser la méthode Clear ()

1
Ziv.Ti

Je viens de rencontrer ceci et la réponse de Claiton Lovato n'a pas fonctionné. Cependant, Iko a fonctionné. Voici une version un peu plus robuste d'Iko. L'inconvénient est x2 voyages vers la base de données - un pour Get et un autre pour l'insertion/mise à jour.

Une solution possible consiste à lire l'objet dans la base de données, à copier les champs dans l'objet et à le sauvegarder. 

public void Save(Company company)
{

    Company dbCompany = null;
    //update
    if (company.Id != 0)
    {
        dbCompany = _companyRepository.Get(company.Id);
        dbCompany.PropertyToUpdate = company.PropertyToUpdate;
    }
    //insert
    else
    {
        dbDefaultFreightTerm = company;
    }
    // Save either the brand new object as an insert
    // Or update the original dbCompany object with an update
    _companyRepository.SaveOrUpdate(company);
}
0
w00ngy