views:

603

answers:

5
+1  Q: 

Mapping hbm.xml

I have a one-to-many relationship but I'd like to get only one instance to have a one-to-one relationship.

I have a class vehicles that may have several owners throughout their life. I only want to map the class to obtain the assets. Is there some way to do this?

The problem is in the hbm.xml file. One vehicle may have several owners throughout their life but I want to obtain only the last owner. I need to filter by vehiculeId, ownerId and EndDate. I want to fill up object owner which is in vehicle.cs with the the assets.

When i write: Vehicule v = VehiculeService.SearchVehicule(id);

I'd like v.Owner must contain the last vehicle's owner.

I can't store the owner's ID on the vehicle table because the owner depend on the date. I can have for example: Vehicle Owner StartDate EndDate 1 1 04/04/2009 04/10/2009 1 2 05/10/2009 NULL

For this reason i must filter by EndDate to have the assets

I have three tables: Vehicle, Owner and OwnerVehicle. The problem is that i must a reference in vehicle.cs to the current owner. And i don't how to do the mapping.

Any help would be appreciated. Thanks

A: 

An easy way to map this is turn it into a Many to One relationship, and store the current owner's ID on the vehicle table. I understand this might be a schema change.

One way to trick this would be to create a view that would essentially be the vehicle table plus it would pull the current ownerid. This way you don't have to change the schema, you would then map to the view instead of the table.

I'm not sure if defining your own loader would work in this case but its one more option to explore.

Edit

I understand your predictament. The easiest way would to be modify the schema and the application to add this additional column one way to fake it would be with a view. So for example

select vehicle.*, owner.ownerid
from vehicle
inner join owner 
  on owner.vehicleid=vehicle.vehicle
and owner.enddate is null

I assume here the current owner has a null end date. Now you change your mapping to map to the view instead of the table. Yes this is a hack but it will work.

I am assuming you still need Owner to be mapped within nHibernate? Another option would be to add a where filter on the Owner's class mapping to filter where end date is null.

Another option you have is to load all the owners up, and push the business rule that defines the current owner to the application tier. Your object might look like:

public Owner CurrentOwner
{
    get 
    {
        return _owners.Find(o=>o.EndDate==DateTime.Min); //Or null if your using a nullable datetime
     }
    set 
    {
        CurrentOwner.EndDate=DateTime.Now;
        _owners.Add(value);
    }
}

}

JoshBerke
I can't store the owner's ID on the vehicle table because the owner depend on the date. I can have for example:Vehicle Owner StartDate EndDate 1 1 04/04/2009 04/10/2009 1 2 05/10/2009 NULLFor this reason i must filter by EndDate to have the assets
A: 

You can use a Criteria (or DetachedCriteria for Spring) object to restrict additional values when performing searches.

Elie
A: 

I suggest to maintain this reference in the business layer and map it as a many-to-one relation. I mean that you set this reference explicitly in you code. This allows you also to find vehicles by its current owners straight forward.

Example:

<class name="Vehicle">
  <map name=AllOwners" >
  ...
  </map>

  <many-to-one name="CurrentOwner" ...>
</class>

public class Vehicle
{
  IList<Owner> AllOwners { get; private set; }
  Owner CurrentOwner { get; set; }
}

public void SetNewOwner(Vehicle v, Owner o)
{
  v.AllOwners.Add(o);
  v.CurrentOwner = o;
}
Stefan Steinegger
I already have a reference to owner in my class vehicle, so vehicle.owner appears by all sides in my code.When i write Vehicle v = VehicleService.Search(id);How v.Vehicle fills up?
Do you mean: "how is v.AllOwners filled up"? NHibernate creates a PersistentBag or something and assignes it to the (private) setter of the property. You can't access the list in the setter of the property, because it is probably not initialized yet.
Stefan Steinegger
A: 

Your relationship is actually many-to-many

An owner could own multiple vehicles

I would keep Vehicles and owners separate and manage their relationship in another entity In another words- you need three tables

Not sure if I changed your question or provided an answer :)

RN
I already have three tables: Vehicle, Owner and OwnerVehicle. The problem is that i must a reference in vehicle.cs to the current owner. And i don't how to do the mapping.
A: 

I don't think it is possible to have NHibernate eager load the "Owner" property automatically. However, you should be able to write a query to get the current owner of a vehicle. It looks like you already have a Vehicle repository/service with VehiculeService. I would add a method like GetCurrentOwner() that takes one parameter, the ID of the vehicle. Then have your Vehicle.Owner property call this method by passing in its own ID.

A Criteria-based query might look like this:

session.CreateCriteria(typeof(Owner))
    .CreateCriteria("OwnedVehicles") // Property path to the OwnerVehicle join table
        .Add(Expression.IsNull("EndDate"))
        .CreateCriteria("Vehicle")
            .Add(Expression.IdEq(id))
            .UniqueResult<Owner>();
Stuart Childs