tags:

views:

234

answers:

6

Hi,

Say I have a Employee class, and a Sales class.

Now say I want to create a page that has a report, displaying all the sales information for a given Employee.

When I return the collection, would I have to define a new class for the colllection returned?

Because I don't want to return ALL the columns/properties for Employee & Sales classes.

I bascially need a subset from each class/entity (basically that map 1:1 to my tables Employee and Sales).

A: 

I depends where you have to pass your result to. Is it in the same process, say in the server, you don't need any special class, because you can make use of lazy loading. You configure NHibernate to only load referenced entities when you access them.

If you send the result over the wire, it is different, because you need to serialize the data and need all properties to be complete. This is actually not a problem of NHibernate, it is a problem of your server interface. Then you need a special DTO (data transfer object) that includes only the data that is needed on the client.

Edit:

I think what you need is lazy loading. There are two different kinds of lazy loading. Lazy loading of collections and lazy loading of references to single entities.

Example:

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; }  
}

Mapping

<!-- 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>

Example Code

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.
Stefan Steinegger
its a web application. The user views the /user/salesreport page. Data is stored in sqlserver.
I don't have experience with .NET web applications. Do you need to serialize the data? Are you still within a session scope when you are building up the page?
Stefan Steinegger
A: 

I don't fully understand your question but the design should be as simple as an Employee and Sale class. The Sale may have an attribute employee and in NHibernate a many-to-one mapping definition. When you select an employee just make a HQL query or a criteria to return the objects Sale that have employee equals to your selected employee.

If it's common to have the employee fetched with all his sales you may an inverse association having an employee with a collection of sales and make it lazy to avoid performance problems.

In both cases you don't need any special class

victor hugo
A: 

NHibernate can do exactly this, using the 'Select New' syntax, which loads a specified field list into your custom query result object. It calls the constructor which matches your queried fields. e.g.

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

A fuller example of the syntax is here

James L
A: 

Nod - Read up on lazy loading (link text) - essentially, on the server side, there's no cost for loading the entity's entire member-set. If you're passing to something outside the server, then the 'best practice' these days is in fact not DTOs, but using a mapped superclass that has the subset of fields you're interested in.

Then, make you're domain entity a subclass of this superclass, with the additional persistable fields. To pass back to a page, simply case to the parent - and on serialization, you'll get exactly what you're after.

Chaos
Ahem, how should this superclass thing work? When you derived a class, and you get the derived class from the database, it is no use to have it referenced as base class. The instance is always of the type of the subclass with all the additional fields.
Stefan Steinegger
Sorry - I didn't mean to make this seem like magic - I probably should have expanded more. You're still essentially using a DTO, but instead of defining the DTO and Entity object as completely separate, you have the aforementioned class hierarchy, and have a method in the Entity class to spawn a new instance of the superclass (the one with limited fields). I'm not suggesting that casting to the superclass is going to 'remove' loaded fields - that would be silly :)
Chaos
I would suggest to use interfaces instead. base classes are always "scary". There are only properties, so the "implementation" actually isn't really something complicated you need to inherit.
Stefan Steinegger
A: 

If I have understood your question correctly, this is what you want.

you need only some fields from Employee & some selected field from Sales.

The simplest thing to do is to map only those fields which you require in the hbm mapping file.

eg: If you only need Id & Name of the employee, then only map those to in the hbm files.

Apologies, if i understood the question wrong.

Sree
A: 

I'm not exactly sure if this will answer your question, but if you just want to return certain properties, you can use a Projection. Or perhaps you want to use query-only properties as Ayende describes in 'NHibernate Query-Only Properties'--although that's for associations generally. Or, there's also NHibernate Filters which returns a subset of records. Or maybe a combination of those.

Mufasa