nhibernate与类设计

nhibernate与类设计,nhibernate,Nhibernate,假设我有一个Employee类和一个Sales类 现在假设我想创建一个页面,其中包含一个报告,显示给定员工的所有销售信息 当我返回集合时,是否必须为返回的集合定义一个新类 因为我不想返回Employee&Sales类的所有列/属性 我基本上需要每个类/实体的子集(基本上是1:1映射到我的表Employee and Sales)。我取决于您必须将结果传递到的位置。它是否在同一个过程中,比如在服务器中,您不需要任何特殊的类,因为您可以利用延迟加载。将NHibernate配置为在访问引用的实体时仅加载

假设我有一个Employee类和一个Sales类

现在假设我想创建一个页面,其中包含一个报告,显示给定员工的所有销售信息

当我返回集合时,是否必须为返回的集合定义一个新类

因为我不想返回Employee&Sales类的所有列/属性


我基本上需要每个类/实体的子集(基本上是1:1映射到我的表Employee and Sales)。

我取决于您必须将结果传递到的位置。它是否在同一个过程中,比如在服务器中,您不需要任何特殊的类,因为您可以利用延迟加载。将NHibernate配置为在访问引用的实体时仅加载它们

如果通过网络发送结果,则情况有所不同,因为您需要序列化数据,并且需要完成所有属性。这实际上不是NHibernate的问题,而是服务器接口的问题。然后,您需要一个特殊的DTO(数据传输对象),它只包括客户机上需要的数据

编辑:


我想你需要的是延迟加载。有两种不同类型的延迟加载。延迟加载集合和延迟加载对单个实体的引用

例如:

class Employee
{
  // make everything virtual to allow NH to build a proxy
  public virtual string name { get; set; }

  // will be lazy loaded
  public virtual IList<Customers> Customers { get; private set; }
  public virtual Employee Boss { get; set; }  
}
class员工
{
//使一切虚拟化,以允许NH构建代理
公共虚拟字符串名称{get;set;}
//将被延迟加载
公共虚拟IList客户{get;private set;}
公共虚拟员工Boss{get;set;}
}
映射

<!-- lazy=true is actually default -->
<class name="Employee" lazy="true">
  <property name="Name"/>
  <property name="Boss"/>

  <!-- lazy=true is actually default -->
  <bag name="Customers" type="Employee" lazy="true">
    <key column="Employee_FK"/>
    <one-to-many class="Employee" />
  </bag>
</class>

示例代码

using (ISession session = CreateSession())
using (ITransaction trx  session.CreateTransaction())
{
  // get a instance of an employee
  // the boss and the customers are not loaded until now
  Employee emp = session.Get<Employee>(empid);

  // emp.Boss is a proxy. This is a subclass of employee
  // generated by NH that implements the lazy loading

  // this loads the boss' data
  if (emp.Boss.Name == "gogogurt")
  {
    // this is your employee
  }

  // this loads the Customers
  if (emp.Customers.Count == 0)
  {
    HumanResources.Fire(emp);
  }

  trx.Commit();
}

// outside the session you cannot access the lazy 
// loaded properties. 
使用(ISession session=CreateSession())
使用(ITransaction trx session.CreateTransaction())
{
//获取一个雇员的实例
//老板和客户到目前为止还没有加载
Employee emp=session.Get(empid);
//emp.Boss是一个代理。这是employee的一个子类
//由实现延迟加载的NH生成
//这将加载boss的数据
如果(emp.Boss.Name==“gogogurt”)
{
//这是你的雇员
}
//这会让客户感到压力
如果(emp.Customers.Count==0)
{
人力资源.消防(emp);
}
提交();
}
//在会话之外,您无法访问该会话
//已加载属性。

我不完全理解您的问题,但设计应该像员工和销售类一样简单。销售可能有一个属性employee,在NHibernate中有一个多对一映射定义。选择员工时,只需执行HQL查询或条件,以返回员工等于所选员工的对象

如果将员工与所有销售一起提取是很常见的,那么您可能会将员工与销售集合进行反向关联,并使其懒惰以避免性能问题


在这两种情况下,您都不需要任何特殊的类,NHibernate可以使用“Select New”(选择新建)语法将指定的字段列表加载到自定义查询结果对象中,从而准确地完成此操作。它调用与查询字段匹配的构造函数。e、 g

SELECT NEW EmployeeSalesSummary(e.Id, e.Name, SUM(s.SaleValue) TotalSales)
FROM Employee e
JOIN etc etc

一个更完整的语法示例是Nod-Read-up-on-lazy-loading()——本质上,在服务器端,加载实体的整个成员集是没有成本的。如果要传递到服务器之外的对象,那么现在的“最佳实践”实际上不是DTO,而是使用一个映射的超类,该超类包含您感兴趣的字段子集


然后,使您的域实体成为这个超类的一个子类,并带有额外的持久化字段。要返回到一个页面,只需将大小写传递给父级—在序列化时,您将得到您想要的内容。

如果我正确理解了您的问题,这就是您想要的

您只需要员工的一些字段和销售人员的一些选定字段

最简单的方法是只映射hbm映射文件中需要的字段

例如:如果您只需要员工的Id和姓名,那么只需将其映射到hbm文件中


抱歉,如果我理解错了这个问题

我不确定这是否能回答您的问题,但如果您只想返回某些属性,可以使用投影。或者,您可能希望使用Ayende在“”中描述的仅查询属性——尽管这通常用于关联。或者,还有一个函数返回记录的子集。或者是两者的结合。

这是一个web应用程序。用户查看/user/salesreport页面。数据存储在sqlserver中。我没有使用.NET web应用程序的经验。您需要序列化数据吗?构建页面时,您是否仍在会话范围内?啊,这个超类应该如何工作?当您派生了一个类,并且从数据库中获取了派生类时,将其作为基类引用是没有用的。实例总是子类的类型,包含所有额外的字段。对不起,我不是想让它看起来像魔术一样-我可能应该扩展得更多。实际上,您仍然在使用DTO,但不是将DTO和实体对象定义为完全独立的,而是使用前面提到的类层次结构,并在实体类中使用一个方法生成超类的新实例(具有有限字段的实例)。我并不是说对超类的强制转换将“删除”加载的字段——这将是愚蠢的:)我建议改为使用接口。基类总是“可怕的”。只有属性,所以“实现”实际上并不是你需要继承的复杂的东西。我认为你需要的是延迟加载。我在回答中添加了一个示例。语法示例链接似乎已失效。