mohaidar
mohaidar

Reputation: 4251

NHibernate Illegally attempted to associate a proxy with two open Sessions

I am stuck from about 12 hours with this error so could any one help me at least to understand what is wrong

Here is my code

public virtual void AssignAssets(IList<long?> assetsIds, ManualAssetAssignment<TAsset>.AssignmentMode mode, IQueryableRepository<TAsset, long?> assetRepository)
{
    this.Assets.Clear();
    if (mode == AssignmentMode.Execlusion)
    {
        //IList<long?> includedAssetsIds = assetRepository.Find().Where(entity => !assetsIds.Contains(entity.Id)).Select(entity => entity.Id).ToList();
        IList<TAsset> includedAssets = assetRepository.Find().Where(entity => !assetsIds.Contains(entity.Id)).ToList();
        foreach (var asset in includedAssets)
        {
            this.Assets.Add(asset);
        }
    }
    else
    {
        foreach (var assetId in assetsIds)
        {
            var asset = assetRepository.Get(assetId);
            this.Assets.Add(asset);
        }
    }
    _areAssetsEvaluated = true;
}

Here is my test

using (var tx = DataSessionContext.Session.BeginTransaction())
{
    atm = new Atm(AtmTestData.AutoCompleteCommand(new Atm.SetupCommand() { }), commandDependencyRegistry);
    atmRepository.Save(atm);
    List<long?> atmIds = new List<long?> { atm.Id };

    var command = AtmExpenseTestData.AutoCompleteCommand(new AssetExpense<Atm>.SetupCommand());
    expense = new AssetExpense<Atm>
    (
        command, commandDependencyRegistry
    );

    var assignCommand1 = new AssetExpense<Atm>.ManualAssetAssignmentCommand()
    {
        AssetsIds = new List<long?>() { atm.Id.Value },
        Mode = ManualAssetAssignment<Atm>.AssignmentMode.Execlusion
    };
    assignCommand1.Execute(expense, commandDependencyRegistry);
    atmAssetExpenseRepository.Save(expense);

    tx.Commit();
}

the weird thing is that if I replace this piece in my code

IList<TAsset> includedAssets = assetRepository.Find().Where(entity => !assetsIds.Contains(entity.Id)).ToList();
foreach (var asset in includedAssets)
{
    this.Assets.Add(asset);
}

By this

IList<long?> includedAssetsIds = assetRepository.Find().Where(entity => !assetsIds.Contains(entity.Id)).Select(entity => entity.Id).ToList();
foreach (var assetId in includedAssetsIds)
{
    this.Assets.Add(assetRepository.Get(assetId));
}

If I replace it the error disappear so could anyone help me to understand this error.

Edit - This might be helpful

From Stack Trace I get that the exception be thrown from this method specifically on line 13 return (TId)((ISession)Session).Save(entity);

public virtual TId Save(TAggregateRoot entity, Action commitPostAction, Action rollbackPostAction, bool propagatePostActionError = false)
{
    if (entity == null)
    {
        throw new ArgumentNullException("entity");
    }

    if (entity is IValidatable)
    {
        ((IValidatable)entity).Validate();
    }
    RegisterPostActions(commitPostAction, rollbackPostAction, propagatePostActionError);
    if (Session is ISession)
    {
        return (TId)((ISession)Session).Save(entity);
    }
    else
    {
        return (TId)((IStatelessSession)Session).Insert(entity);
    }
}

Upvotes: 0

Views: 3380

Answers (1)

Rabban
Rabban

Reputation: 2581

Lists(IList, ISet...) and References from Entities are Proxies in NHibernate. This allows you to lazy load them. The exception tells you that you are using one of this proxies in two open sessions. That means you are loading a entity in one session and try to save it in another. If this is intended, close the first session before you use the next one. I would recommend to use the UnitOfWork Pattern to prevent such behaviour.

Upvotes: 2

Related Questions