tags:

views:

623

answers:

2

I started using NHibernate this week (struggling). I have a small application with 3 tables (I use 2 for now). Table currency and table country here are the mapping files.

<class name="dataprovider.Country,dataprovider" table="country">
    <id name="CountryId" column="country_id" unsaved-value="0">
        <generator class="native"/>
    </id>
    <!--<bag name="BatchList" inverse="true" lazy="true" >
        <key column="country_id" />
        <one-to-many class="Batch" />
    </bag>
    <bag name="PrinterList" inverse="true" lazy="true" >
        <key column="country_id" />
        <one-to-many class="Printer" />
    </bag>-->
    <many-to-one name="CurrencyId" column="currency_id" class="Currency"  cascade="save-update"/>
    <!--<property column="currency_id" name="Currency_Id"/>-->
    <property column="name" name="Name"/>
    <property column="region" name="Region" />
    <property column="comments" name="Comments"/>
</class>

The currency mapping file:

<class name="dataprovider.Currency, dataprovider" table="currency">
    <id name="CurrencyId" column="currency_id" >
        <generator class="native"/>
    </id>
    <bag name="CountryList" inverse="true" lazy="true" >
        <key column="currency_id" />
        <one-to-many class="Country" />
    </bag>
    <!--<bag name="DenominationList" inverse="true" lazy="true" >
        <key column="currency_id" />
        <one-to-many class="Denomination" />
    </bag>-->
    <property column="name" name="Name"/>
    <property column="authorizer" name="Authorizer"  />
    <property column="date_created"  name="DateCreated" type="DateTime" not-null="true" />
    <property column="comments"  name="Comments"  />

The many to one relationship that country hold create an attribute of the type Currency in the country persistence class. Now while my test can_add_currency and can_add_country succeeded (I export the schema) I have null value in the table country on the field currency_id.

Here is the test code:

[Test]
    public void can_add_new_country()
    {
        CountryManager cm = new CountryManager();

        Country country = new Country();
        //country.CurrencyId = CurrencyManager.GetCurrencyById(1);
        country.CurrencyId = new CurrencyManager().GetCurrencyById(1);
        country.Name = "POUND";
        country.Region = "ENGLAND";
        country.Comments = "the comment";

        cm.Add(country);

        using(ISession session = _sessionFactory.OpenSession())
        {
            Country fromdb = session.Get<Country>(country.CountryId);
            Assert.IsNotNull(fromdb);
            Assert.AreNotSame(fromdb, country);
        }
    }

    public Currency GetCurrencyById(int currency_id)
    {//GetCurrencyById from CurrencyManger class
        try
        {
            using(ISession session = NHibernateHelper.OpenSession())
            {
                return session.Get<Currency>(currency_id);

            }
        } catch (Exception ex)
        {
            return null;
        }
    }

The question is: how to insert into table country with the currency_id of an existing currency_id from the table currency?

How do you guys/gals do it? I'm seriously stuck and a 2 day small project is taking me one week now.

A: 

Set cascade="save-update" on your bag name="CountryList". If that doesn't work, it may be helpful to post your code for CountryManager.Add() to see how the saving is taking place.

In response to your second question, if I understand it correctly, this is how NHibernate treats mapped collections:

You mapped the collection as lazy, so loading the object will not load all the elements of the collection at the same time. Instead, when you first access the collection NHibernate will query the database to fill the collection and return it. So, when you first do something like:

var countries = currency.CountryList;

or

foreach (Country country in currency.CountryList)

NHibernate will silently execute a query similar to:

SELECT * FROM country WHERE currency_id = ?

And then build a collection of Country objects to return (and cache so that the query is not run again).

Basically, through the mapping file you've already told NHibernate all about your two entities (Country and Currency) and how they are related so it knows how to build the queries to access the data. Similarly, it keeps track of what was in the collection so when you add or remove items, it can compare what was changed and execute the appropriate INSERT or REMOVE statements.

So, the way to use collections mapped by NHibernate is to use them just as you would with a normal .NET collection. Add and remove items at your will. Just when you are finished, make sure you tell NHibernate to persist the changes you made to the database, either by calling session.Save() or session.Delete() on every item you add/remove or (if you have set cascading, like you have) simple call session.Save() on the parent object that contains the collection.

Stuart Childs
A: 

My cascade was rather on the this side:

<many-to-one name="CurrencyId" column="currency_id" class="Currency"  cascade="save-update"/>

After I changed it it wasn't working at first even though I rebuild the solution. Then I did another test from the Currency_Test class: can_get_currency_by_id which call the same function GetCurrncyById and I could have an object while from can_add_new_country the same function returns null.

Then I realise that the ExportSchema of either Country_Test [Setup] or Currency_Test is not creating the database on time for the can_add_new_product to have a currency object. That's why it's returning null object.

Now not to abuse; but can you tell me how to use IList<Counrty>CountryList? I don't know if I put it well. From my understanding it should store all country objects using the same currency (currency_id reference). How does NHibernate do that?

black sensei
I updated my answer, hopefully it answers the question you are asking.
Stuart Childs
thanks i've read it.it's a bit clear now.I'm wondering what will happen to nhibernate now that Jboss seems to have bought hibernate.Thanks again man!
black sensei