c# - 非法尝试将一个集合与两个打开的 session 相关联 fluent nhibernate

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

我有这个异常“非法尝试将一个集合与两个打开的 session 相关联”,每次我保存包含子集合的实体时它都会引发。 我谷歌它。我发现我在调用保存时打开了两个或多个 session ,但我确定我只使用了一个 session 。 我哪里做错了?我该如何解决这个问题? 注意:我使用的是 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; }
    }
}

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

最佳答案

另外,为了完整性,通常有两类问题:

  1. 通常与管理不当的 DAO 对象及其自己的 ISession 创建有关:

    在上面定义的示例中,可能有两个对象与存储库一起工作:(a) persistor 和 (b) finder

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

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

    很可能手机 是由不同的 session 加载的。不是通过处理 Employee 的“当前”。

    所以最可疑的是调用 Redirect()。如果是,发生的事情是我们在一个 Controller 生命周期中加载一个对象 - 将其放入 Temp 字典 - 调用 Redirectother controller -现在有一个新 session 以及一个与旧的、关闭的 session 关联的旧对象。

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

关于c# - 非法尝试将一个集合与两个打开的 session 相关联 fluent nhibernate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25063421/

相关文章:

java - 哪一个负责生成http session ID?客户端浏览器、服务器或两者?

postgresql - 哪个 postgres 系统表存储 PID 到 session 授权的映射?

sql-server - 如何在 SQL Server session 中设置自动提交?

c# - asp 的 Javascript 更多/更少文本按钮 :label

c# - 在 C# .NET 中将字符串格式化为固定长度

asp.net-mvc-4 - 根本无法让 SignalR (asp.net mvc4) 和 require.js 一起工作

iis - ASP.NET MVC4 可以在 IIS7.5、.NET Framework 4 上运行吗?

asp.net-mvc-4 - 如何在 Kendo UI Grid 中的页面加载时展开所有行?

javascript - 创建 C# 256 位 AES 加密,如 cryptoJS

c# - BlockingCollection.TakeFromAny 方法是否适合构建阻塞优先级队列?