【问题标题】:illegal attempt to associate a collection with two open sessions fluent nhibernate非法尝试将集合与两个打开的会话相关联流利的休眠
【发布时间】:2014-09-23 15:57:35
【问题描述】:

我有这个异常“非法尝试将一个集合与两个打开的会话相关联”,每次我保存实体包含子集合时都会引发。 我谷歌它。我发现我在调用 save 时打开了两个或多个会话,但我确定我只使用了一个会话。 我哪里做错了?我该如何解决这个问题? 注意:我使用的是 MVC4 和流利的 NHibernate。

实体:

public class Employee : EntityBase<int>
{
    public Employee()
        : base()
    {
        Phones = new List<Phone>();
    }

    public Employee(int id) : this() { Id = id; }
    [Browsable(false)]
    public override ApprovalBase Approval
    {
        get;
        set;
    }

    public virtual string Name { get; set; }
    public virtual string Job { get; set; }

    [Browsable(false)]
    public virtual IList<Phone> Phones { get; set; }
}
public class Phone : EntityBase<int>
{
    public Phone()
        : base()
    {
    }
    public Phone(int id) : this() { Id = id; }
    public override ApprovalBase Approval
    {
        get;
        set;
    }

    public virtual string PhoneNumber { get; set; }
    public virtual string PhoneType { get; set; }
    public virtual int EmployeeId { get; set; }

    public virtual Employee Employee { get; set; }
}

映射:

public sealed class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        Table("dbo.Employee");

        Id(x => x.Id).Column("EmployeeId");
        Map(x => x.Name);
        Map(x => x.Job);
        HasMany(x => x.Phones).KeyColumn("EmployeeId").Table("dbo.Phone").Cascade.All().Inverse();
    }
}
public sealed class PhoneMap : ClassMap<Phone>
{
    public PhoneMap()
    {
        Table("dbo.Phone");
        Id(x => x.Id).Column("PhoneId");
        Map(x => x.PhoneNumber);
        Map(x => x.PhoneType);
        Map(x => x.EmployeeId);
        References(x => x.Employee).Column("EmployeeId")
            .Not.Update()
            .Not.Insert();
    }
}

存储库:

public abstract class RepositoryBase<TEntity, TIdentity>
    : IRepository<TEntity, TIdentity>
    where TEntity : EntityBase<TIdentity>
    where TIdentity : IComparable
{
    private readonly IPersistor<TEntity, TIdentity> persistor; //contains the session to operate with the database
    public IPersistor<TEntity, TIdentity> Persistor { get { return persistor; } }

    private readonly IFinder<TEntity, TIdentity> finder;
    public IFinder<TEntity, TIdentity> Finder { get { return finder; } }

    private RepositoryBase() { }

    public RepositoryBase(
        IPersistor<TEntity, TIdentity> persistor,
        IFinder<TEntity, TIdentity> finder)
    {
        this.persistor = persistor;
        this.finder = finder;
        this.finder.DataSource = Query();
    }

    // Get entity by ID
    public virtual TEntity Get(TIdentity id)
    {
        return persistor.Get(id);
    }

    /// <summary>
    /// Validate and Save the entity. If the validation failed, will not save the entity,
    /// but returns back list of error messages.
    /// </summary>
    public virtual IList<String> Save(TEntity entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");

        IList<String> errors = entity.Validate();

        if (errors.Count == 0)
        {
            persistor.Save(entity);
        }

        return errors;
    }

    // Delete entity from persistance repository
    public virtual void Delete(TIdentity id)
    {
        persistor.Delete(id);
    }

    /// Gets IQueryable which we use from the concrete
    /// implementation of repository to implement our 
    /// query methods (FindBy).
    protected IQueryable<TEntity> Query()
    {
        return persistor.Query();
    }

    public IList<TEntity> GetAll()
    {
        return persistor.Query().ToList();
    }
}

public class EmployeeRepository : RepositoryBase<Employee, int>, IEmployeeRepository
{
    public EmployeeRepository(
        IPersistor<Employee, int> persistor,
        IEmployeeFinder entityFinder)
        : base(persistor, entityFinder) { }

    public IEmployeeFinder Find
    {
        get { return (IEmployeeFinder)Finder; }
    }
}
public class PhoneRepository : RepositoryBase<Phone, int>, IPhoneRepository
{
    public PhoneRepository(
        IPersistor<Phone, int> persistor,
        IPhoneFinder entityFinder)
        : base(persistor, entityFinder) { }

    public IPhoneFinder Find
    {
        get { return (IPhoneFinder)Finder; }
    }
}

填写Employee的所有信息并添加电话集合后,当我按保存时,信息尚未保存在数据库中。经过一番调试,我发现当我的程序到达“Session.SaveOrUpdate(entity);”时出现上述异常。 如何解决这个问题?

【问题讨论】:

  • 我猜:您确实有两个人在处理您的存储库:persistor 先生和finder 先生。他们都有自己的ISessioninstance。如果finder 确实成功并找到了一些东西......例如Phones ... 实体 Employee 分配它们并尝试保存 ... 但是:Phones 在不同的会话中 (instance)然后Employee。我猜,但事实上我确信...... ;)
  • 但是,我查看了代码,发现我正在使用一个会话,因为我的 MVC4 控制器在构造函数中启动了一个会话,并在员工的存储库中使用了这个会话,员工有电话,它们之间的关系是一对多的(请参阅映射器)。我哪里做错了?
  • 异常很清楚,我们都明白。最有可能(肯定)电话加载了不同的会话,这是“当前” - 处理员工。如果会话真的很常见,那么唯一的其他选择是您正在使用“重定向”。如果是,您可以在一个控制器生命周期内加载一个对象 - 将其放入 Temp - 调用重定向到另一个控制器 - 现在有新会话和与旧会话关联的旧对象(关闭一个)。解决方案:确保您所做的所有事情都在一个地方。想想你目前的东西,你一定会得到它;)
  • 感谢 Radim Kohler,这非常有帮助。我会尽快发布解决方案。

标签: c# asp.net-mvc-4 session nhibernate fluent-nhibernate


【解决方案1】:

另外,为了完整起见,通常有两种类型的问题:

  1. 通常与管理不当的 DAO 对象相关,并创建了自己的 ISession

    如上面定义的示例,可能有两个对象可以与存储库一起使用:(a) persistor 和 (b) finder

    他们每个人都有一个ISession 的实例。如果finder 成功并找到了某些东西(例如Phones),实体Employee 会尝试保存,但Phones 在不同的会话中员工

  2. 经常与 ASP.NET MVC 及其Redirect() 操作结果相关:

    很可能电话是由不同的会话加载的。不是由处理 Employee 的“当前”。

    所以最可疑的是电话Redirect()。如果是,我们会在 一个控制器的生命周期中加载一个对象 - 将其放入 Temp 字典 - 调用 Redirect其他控制器 -现在有一个新会话以及一个与旧的、已关闭的会话相关联的旧对象。

解决方案:请确保所有 DAO 处理都是 ISession 范围的一部分。不要在会话之间传输任何数据(也不在控制器重定向之间)...

【讨论】:

  • 这就是我的应用程序的问题。我将“EmployeeController”和“PhoneController”分开,并在它们之间使用 sessin["Phones"] 来管理 MVC4 中的一对多关系。我通过在 EmployeeContoller 中创建Phone 控制器功能来解决它​​,问题解决了:)
【解决方案2】:

我在每个使用静态变量的方法中都使用 lock 语句解决了这个问题,因为问题的根源与同步有关。

这是一个简单的例子来说明我的解决方案:

private static int sharedVariable;
private static object _syncronizationObject = new Object();

public void MethodThatUsesStaticVariable(int newValue)
{
    // This lock prevents concurrency problems, and this is what solved the issue for me.
    lock(_syncronizationObject)
    {
        sharedVariable = newValue;
    }
}

【讨论】:

    猜你喜欢
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2011-03-06
    • 2015-03-23
    相关资源
    最近更新 更多