views:

236

answers:

4

I have two tables Deal and Cost. Costs can be of a number of types, eg Planned, Unplanned. Every deal can have one an only one of each type of cost. This is easy enough to map as a many-to-one on deal, reulting in an IList of Costs. But what I want is to create a costs object that has named properties for each cost. So that for a database that looks like this:

Deal:               Cost
ID   Name           ID   DealID   Type        Value
---------           -------------------------------
1    Test           1    1        Planned     10
                    2    1        Unplanned   5

it is accessible like this

Deal.Costs.Planned = 10m;
Deal.Costs.Unplanned = 5m;

How is the best way to go about mapping this? Should I even be mapping it or should I just write the properties by hand to query the underlying collection?

The difficulty as i see it is mapping the properties of cost so that they map to different rows in teh same table. Using one of the columns as a discriminator.

A: 

This doesn't really sound to me like Costs is a list.

I would map the Cost as a property on Deal. If you want to keep the Deal.Costs.Planned syntax you can use a Component mapping.

Derek Ekins
That makes sense. But how can I have the component mapping select different rows from the Costs table for each property of list, I need to set some sort of discriminator I guess but I have never seen this done.
Jack Ryan
If you map a Cost as a property of deal then you will need to add a foreign key to the deal table. I am assuming of course you have control of the db.
Derek Ekins
The DB already has that structure. The difficulty is in mapping the properties to different rows of the same table. Question has been edited to be clearer on this.
Jack Ryan
Hmm, well as far as I am aware there is no way of mapping this. I think your best bet is to take an approach like Matt suggested. You can make your collection private so that there is no way people can manually add/remove items from the collection.Then your properties will need to contain some logic to keep the internal collection up to date. So when you set a value it will add the item to the collection.
Derek Ekins
A: 

Write the properties methods by hand:

public class Deal
{
    public virtual Cost GetPlannedCost() 
    {
        return _costs.FirstOrDefault(x => x.IsPlanned()); 
    }

    public virtual Cost GetUnplannedCost() {}
    {
        return _costs.FirstOrDefault(x => x.IsUnplanned()); 
    }

    public virtual Cost[] GetAllCosts() 
    {
        return _costs.ToArray(); 
    }

    private ISet<Cost> _costs = new HashedSet<Cost>();
}
Matt Hinze
This doenst allow for my notation of deal.costs.CostName. Thats the problematic part of the mapping for me.
Jack Ryan
Why are you concerned about your notation at this point?
Matt Hinze
A: 

I would map Costs as a private collection and expose Planned and Unplanned costs on Deal. This would allow you to enforce "Every deal can have one an only one of each type of cost" as a business rule. It would look something like this:

public class Deal
{
    private IList<Cost> _costs = new List<Cost>(2); // map this collection

    public Cost PlannedCost
    {
        get { return _costs.FirstOrDefault(c => c.Type == CostType.Planned); }
        set
        {
            var plannedCost = _costs.FirstOrDefault(c => c.Type == CostType.Planned);
            if (plannedCost != null)
            {
                _costs.Remove(plannedCost);
            }
            _costs.Add(value);
        }
    }

    public Cost UnplannedCost { // similarly }
}
Jamie Ide
A: 

You can have formula properties in your class using Formula tag of NHibernate mapping.A formula is simply a SQL statement that will be inserted as a subquery in a mapping query. Obviously Formula properties are read only and can't be updated.

Since you want to calculate these properties for each Deal you should add them as Deal properties (if you'd like to use formula) thus you will have:

Deal.UnPlannedCosts
Deal.PlannedCosts

Here's an article that explains formula properties.

Beatles1692