C# 使用NHibernate时如何处理不同的实体实例?
ORMs和对象标识有一个众所周知的问题。就ORM而言,如果实体具有相同的ID,则它们是相等的。当然,这不适用于被视为不存在的临时实例 但就OO代码而言,如果对象引用同一实例,则认为它们是相等的。也就是说,除非覆盖C# 使用NHibernate时如何处理不同的实体实例?,c#,nhibernate,fluent-nhibernate,identity,equality,C#,Nhibernate,Fluent Nhibernate,Identity,Equality,ORMs和对象标识有一个众所周知的问题。就ORM而言,如果实体具有相同的ID,则它们是相等的。当然,这不适用于被视为不存在的临时实例 但就OO代码而言,如果对象引用同一实例,则认为它们是相等的。也就是说,除非覆盖等于和/或== 这很好,但在实践中又意味着什么呢?下面是一个非常简单的域模型示例: namespace TryHibernate.Example { public abstract class Entity { public int Id { get; set; } } pub
等于
和/或==
这很好,但在实践中又意味着什么呢?下面是一个非常简单的域模型示例:
namespace TryHibernate.Example
{
public abstract class Entity
{
public int Id { get; set; }
}
public class Employee : Entity
{
public string Name { get; set; }
public IList<Task> Tasks { get; set; }
public Employee()
{
Tasks = new List<Task>();
}
}
public class Task : Entity
{
public Employee Assignee { get; set; }
public Job Job { get; set; }
}
public class Job : Entity
{
public string Description { get; set; }
}
} // namespace
namespace TryHibernate.Example
{
公共抽象类实体
{
公共int Id{get;set;}
}
公共类雇员:实体
{
公共字符串名称{get;set;}
公共IList任务{get;set;}
公职人员()
{
任务=新列表();
}
}
公共类任务:实体
{
公共雇员受让人{get;set;}
公共作业作业{get;set;}
}
公共类作业:实体
{
公共字符串说明{get;set;}
}
}//名称空间
下面是使用它的示例代码:
using (ISessionFactory sessionFactory = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile("temp.sqlite").ShowSql())
//.Cache(c => c.UseSecondLevelCache().UseQueryCache().ProviderClass<HashtableCacheProvider>())
.Mappings(m => m.AutoMappings.Add(
AutoMap.AssemblyOf<Entity>()
.Where(type => type.Namespace == typeof(Entity).Namespace)
.Conventions.Add(DefaultLazy.Never())
.Conventions.Add(DefaultCascade.None())
//.Conventions.Add(ConventionBuilder.Class.Always(c => c.Cache.ReadWrite()))
).ExportTo("hbm")
).ExposeConfiguration(c => new SchemaExport(c).Create(true, true))
.BuildSessionFactory())
{
Job job = new Job() { Description = "A very important job" };
Employee empl = new Employee() { Name = "John Smith" };
Task task = new Task() { Job = job, Assignee = empl };
using (ISession db = sessionFactory.OpenSession())
using (ITransaction t = db.BeginTransaction())
{
db.Save(job);
db.Save(empl);
empl.Tasks.Add(task);
db.Save(task);
t.Commit();
}
IList<Job> jobs;
using (ISession db = sessionFactory.OpenSession())
{
jobs = db.QueryOver<Job>().List();
}
IList<Employee> employees;
using (ISession db = sessionFactory.OpenSession())
{
employees = db.QueryOver<Employee>().List();
}
jobs[0].Description = "A totally unimportant job";
Console.WriteLine(employees[0].Tasks[0].Job.Description);
}
使用(ISessionFactory sessionFactory=fluntly.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile(“temp.sqlite”).ShowSql())
//.Cache(c=>c.UseSecondLevelCache().UseQueryCache().ProviderClass())
.Mappings(m=>m.AutoMappings.Add(
自动映射
.Where(type=>type.Namespace==typeof(Entity.Namespace)
.Conventions.Add(DefaultLazy.Never())
.Conventions.Add(DefaultCascade.None())
//.Conventions.Add(ConventionBuilder.Class.Always(c=>c.Cache.ReadWrite()))
).出口至(“hbm”)
).ExposeConfiguration(c=>newschemaexport(c).Create(true,true))
.BuildSessionFactory())
{
Job Job=new Job(){Description=“一项非常重要的工作”};
Employee Employee=new Employee(){Name=“John Smith”};
任务Task=newtask(){Job=Job,assignment=emp};
使用(ISession db=sessionFactory.OpenSession())
使用(ITransaction t=db.BeginTransaction())
{
db.Save(作业);
db.Save(emp);
emp.Tasks.Add(任务);
db.Save(任务);
t、 提交();
}
国际劳工组织的工作;
使用(ISession db=sessionFactory.OpenSession())
{
jobs=db.QueryOver().List();
}
IList员工;
使用(ISession db=sessionFactory.OpenSession())
{
employees=db.QueryOver().List();
}
作业[0]。Description=“完全不重要的作业”;
Console.WriteLine(员工[0]。任务[0]。职务。说明);
}
当然,它打印了“一项非常重要的工作”。启用二级缓存(注释掉)不会改变它,尽管在某些情况下会减少数据库命中率。显然这是因为NHibernate缓存数据,而不是对象实例
当然,在这里重写相等/散列代码没有帮助,因为不是相等引起问题。事实上,我这里有两个相同的例子
这都很好,但如何处理呢?有几种选择,但对我来说都不太有吸引力:
我还错过了其他选择吗?令我惊讶的是,关于这个问题的信息如此之少。我能找到的最好的方法是,但它只处理平等问题。好的,这是我的想法。基本上,这是选项3,有一些调整。我的回购类现在看起来像这样:
public class Repo : IDisposable
{
private ISessionFactory sessionFactory;
private ISession session;
public Repo(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
this.session = sessionFactory.OpenSession();
session.Disconnect();
}
public void Dispose()
{
try
{
session.Dispose();
}
finally
{
sessionFactory.Dispose();
}
}
public void Save(Entity entity)
{
using (Connection connection = new Connection(session))
using (ITransaction t = session.BeginTransaction())
{
session.Save(entity);
t.Commit();
}
}
public IList<T> GetList<T>() where T : Entity
{
using (Connection connection = new Connection(session))
{
return session.QueryOver<T>().List();
}
}
private class Connection : IDisposable
{
private ISession session;
internal Connection(ISession session)
{
this.session = session;
session.Reconnect();
}
public void Dispose()
{
session.Disconnect();
}
}
}
公共类回购:IDisposable
{
私人ISessionFactory sessionFactory;
非公开会议;
公开回购(ISessionFactory sessionFactory)
{
this.sessionFactory=sessionFactory;
this.session=sessionFactory.OpenSession();
session.Disconnect();
}
公共空间处置()
{
尝试
{
session.Dispose();
}
最后
{
sessionFactory.Dispose();
}
}
公共作废保存(实体)
{
使用(连接=新连接(会话))
使用(ITransaction t=session.BeginTransaction())
{
session.Save(实体);
t、 提交();
}
}
public IList GetList(),其中T:Entity
{
使用(连接)
using (Repo db = new Repo(sessionFactory))
{
Job job = new Job() { Description = "A very important job" };
Employee empl = new Employee() { Name = "John Smith" };
Task task = new Task() { Job = job, Assignee = empl };
db.Save(job);
db.Save(empl);
empl.Tasks.Add(task);
db.Save(task);
IList<Job> jobs;
jobs = db.GetList<Job>();
IList<Employee> employees;
employees = db.GetList<Employee>();
jobs[0].Description = "A totally unimportant job";
Console.WriteLine(employees[0].Tasks[0].Job.Description);
}