我有一个类,Task,它有一个属性TaskLibrary,它将加载并运行一些代码。因此,任何任务都有一个库,但任何库都可以有很多任务。我的问题是我的确保任务的Library属性不为null的测试失败(所以它可能只是我的测试)。我的课程实际上是这样的:
public class Task
{
public virtual int TaskId {get;set;}
public virtual string Locked {get;set;}
public virtual int Status {get;set;}
public virtual TaskLibrary Library {get;set;}
}
public class TaskLibrary
{
public virtual int LibraryId {get;set}
public virtual string Name {get;set;}
public virtual string Description {get;set;}
public virtual byte[] Dll {get;set}
public virtual IEnumerable<Task> Tasks {get;set;}
}
我的NHibernate映射看起来像这样:
<class name="Task">
<id name="Id" column="TaskId" type="Int32" unsaved-value="-1">
<generator class="identity"/>
</id>
<property name="Locked" column="Locked"/>
<property name="Status" column="Status"/>
<many-to-one name="Library" class="TaskLibrary" fetch="join"/>
</class>
<class name="TaskLibrary">
<id name="Id" column="LibraryId">
<generator class="identity"/>
</id>
<property name="Name"/>
<property name="Description"/>
<property name="Dll"/>
<set name="Tasks" lazy="true">
<key column="LibraryId"/>
<one-to-many class="Task"/>
</set>
</class>
我的测试类看起来像这样:
[TestFixture]
public class TaskRepositoryFixture
{
private ISessionFactory _sessionFactory;
private Configuration _configuration;
private readonly Task[] _tasks = new[]
{
new Task {Id = 1, Status = 1, Locked = 0, Library = new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
new Task {Id = 2, Status = 1, Locked = 0, Library = new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
new Task {Id = 3, Status = 1, Locked = 0, Library = new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
new Task {Id = 4, Status = 1, Locked = 0, Library = new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
new Task {Id = 5, Status = 1, Locked = 0, Library = new TaskLibrary { Id =3, Description = "Test Library 3", Name = "Tast3.dll", Type = "RunnableTask", Dll = Encoding.ASCII.GetBytes("test binary data")}},
};
private readonly TaskLibrary[] _libraries = new[]
{
new TaskLibrary { Id =1, Description = "Test Library", Name = "Tast.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")},
new TaskLibrary { Id =2, Description = "Test Library 2", Name = "Tast2.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")},
new TaskLibrary { Id =3, Description = "Test Library 3", Name = "Tast3.dll", Type = "RunnableTask", BinaryDll = Encoding.ASCII.GetBytes("test binary data")}
};
private void CreateInitialData()
{
using (ISession session = _sessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
foreach (var lib in _libraries)
session.Save(lib);
foreach (var task in _tasks)
session.Save(task);
transaction.Commit();
}
}
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
_configuration = new Configuration();
_configuration.Configure();
_configuration.AddAssembly("DistPollAutoTasksShared");
_sessionFactory = _configuration.BuildSessionFactory();
}
[SetUp]
public void SetupContext()
{
new SchemaExport(_configuration).Execute(false, true, false, false);
CreateInitialData();
}
[Test]
public void CanGetLibraryFromTask()
{
ITaskRepository repository = new TaskRepository();
var fromDb = repository.GetById(_tasks[0].Id);
Assert.IsNotNull(fromDb.Library);
Assert.IsNotNull(fromDb.Library.Dll);
}
}
并且,MSSQL2000数据库中的Tasks表是:
CREATE TABLE [dbo].[Tasks](
[TaskId] [int] IDENTITY(1,1) NOT NULL,
[TaskLibrary] [int] NOT NULL,
[Status] [int] NOT NULL,
[Locked] [int] NOT NULL
)
如果你还和我在一起......
从我的Task类中,我只想要一个Library属性的TaskLibrary类的实例。此外,如果我正在使用库本身,我希望能够使用该库懒惰地检索所有任务的IEnumerable。但是,当我运行测试时,我收到此错误:
TestCase 'DistPollAutoTasksShared.Tests.TaskRepositoryFixture.CanGetLibraryFromTask'
failed: NHibernate.LazyInitializationException : Could not initialize proxy - no Session.
at NHibernate.Proxy.AbstractLazyInitializer.Initialize()
at NHibernate.Proxy.AbstractLazyInitializer.GetImplementation()
at NHibernate.Proxy.Poco.Castle.CastleLazyInitializer.Intercept(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at TaskLibraryProxy2bd44073e90f47298039abfbfda11492.get_Dll()
这是我第一次使用NHibernate,所以我还在学习。我真的想要获得基础知识的良好基础,所以我一直坚持到这里。任何帮助,建议,阅读材料(我已阅读所有this question's建议和其他一些)将不胜感激。
修改
更改fetch =“join”后,我从Task类中获得了我想要的功能。但是,我为TaskLibrary类的Tasks属性添加了另一个测试:
[Test]
public void CanGetTasksByLibrary()
{
ITaskLibraryRepository repository = new TaskLibraryRepository();
var fromDb = repository.GetById(_libraries[0].Id).Tasks;
Assert.IsNotNull(fromDb);
Assert.True(fromDb.Count() == 2, "Cannot get IEnumerable<Task> from TaskLibrary");
}
但是,断言失败并出现此错误(我已更新上面的代码以反映我所做的任何更改):
TestCase 'DistPollAutoTasksShared.Tests.TaskLibraryRepositoryFixture.CanGetTasksByLibrary'
failed:
Cannot get IEnumerable<Tasks> from TaskLibrary
Expected: True
But was: False
答案 0 :(得分:1)
<many-to-one name="Library" class="TaskLibrary" fetch="join" />
这将在每个选择中加入图书馆。
<many-to-one name="Library" class="TaskLibrary" lazy="false" />
这将急切地为库执行单独的选择。
否则,如果只设置fetch =“select”(这是默认值),它将延迟加载库。
http://ayende.com/Blog/archive/2009/04/09/nhibernate-mapping-ltmany-to-onegt.aspx
http://nhibernate.info/doc/nh/en/index.html#collections-lazy
答案 1 :(得分:0)
你是否尝试在映射中设置Lazy =“false”? http://code-redefined.blogspot.com/2007/07/hibernate-lazy-fetch-problems-could-not.html
答案 2 :(得分:0)
不要更改测试的映射,您的需求应该驱动对象的映射方式。 您的存储库方法在从数据库获取后关闭会话。您需要为整个测试方法保持会话打开。 要弄清楚如何做到这一点,您需要告诉我们您如何管理会话。这些是绑定到事务/ threadlocal吗?