1

我遇到了一个真正令人沮丧的问题,并花了几个小时尝试各种方法来解决。当集合在某些对象上延迟加载时,它会抛出 LazyInitializationException 说明没有会话或会话已关闭。将代码取出到干净的控制台应用程序中进行测试后 - 我确信会话根本无法关闭!这是代码:

    private static ISessionFactory _sessionFactory;

    static void Main(string[] args)
    {
        _sessionFactory = BuildFactory(@"*<ThisIsMyConnectionString>*");
        using (var session = _sessionFactory.OpenSession())
        {
            var allContacts = session.Query<Contact>().Where(x=>x.EmployeeId.HasValue);
            foreach (var contact in allContacts)
            {
                var allServices = contact.EmployeeServices.ToArray();
            }
            session.Dispose();
        }
    }

    private static ISessionFactory BuildFactory(string connectionString = null)
    {
        return Fluently.Configure()
                       .Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2008.ConnectionString(connectionString))
                       .Mappings(m =>
                           {
                               m.FluentMappings.Conventions.AddFromAssemblyOf<TableNameConvention>();
                               m.FluentMappings.AddFromAssemblyOf<KioskAdapterConfigMapping>();
                           })
                       .BuildConfiguration().BuildSessionFactory();
    }

这是我的(流利的)映射:

public ServiceMapping()
    {
        Table("tblServices");
        Id(x => x.Id, "ServiceId");
        Map(x => x.Name);
    }
public ContactMapping()
     {
         Table("tblContacts");
         Id(x => x.Id, "ContactId");
         Map(x => x.EmployeeId);
         HasManyToMany(x => x.EmployeeServices)
             .Table("lnkEmployeeService")
             .ParentKeyColumn("EmployeeId")
             .PropertyRef("EmployeeId")
             .ChildKeyColumn("ServiceId")
             .NotFound.Ignore();
     }

会话到底是如何关闭的?一些数据库记录在“lnkEmployeeService”表中没有任何记录,但所有外键都到位且有效。此外,链接表确实有额外的列,实际上是与其他列的复合键,但我不关心其余数据。

4

2 回答 2

1

问题隐藏在事实中,EmployeeServices集合通过非唯一值"EmployeeId"映射到联系人。

换句话说,让我们假设三个联系人

ContactId, EmployeeId
1        , 1
2        , 2
3        , 2

现在,我们指示 NHibernate 准备好加载 3 个集合。对于每个联系人,它们将/应该/必须是唯一的。所以在 ISession 中,它们可以通过它们的唯一标识符来保存。在 NOT property-ref 映射的情况下,它们将类似于:

CollectionId - Collection
1            - the first collection of all Services related to contact with ID 1 
2            - the first collection of all Services related to contact with ID 2 
3            - the first collection of all Services related to contact with ID 3

但是我们这里确实有一个问题,因为我们的集合的唯一标识符是

CollectionId - Collection
1            ...
2            ...
2            - here we go... this (collection) or the previous 
               must now be removed from a session... 
               no way how to load/handle it any more

关键,必须是唯一的,这就是重点,即使这是property-ref. 在文档稍有不同的地方,我们可以看到5.1.10。多对一

property-ref 属性应仅用于映射遗留数据,其中外键引用关联表的唯一键而不是主键。

虽然没有对<bag>映射进行解释,但逻辑仍然相同

于 2013-09-27T10:07:26.120 回答
0

我认为问题在于您正在对包装在 using 块中的 IDisposable 调用 Dispose。using 块相当于写

var myDisposable = new SomeIDisposableImplementation();
try { ... }
finally 
{ 
    if(myDisposable != null) myDisposable.Dispose(); 
}

在您的代码中 Dispose 被调用两次。我的猜测是这导致了问题,但我无法在简单的测试中复制异常。

于 2013-09-27T13:07:25.407 回答