atam
atam

Reputation: 101

nhibernate - sproutcore : How to only retrieve reference ID's and not load the reference/relation?

I use as a front-end sproutcore, and as back-end an nhibernate driven openrasta REST solution.

In sproutcore, references are actualy ID's / guid's. So an Address entity in the Sproutcore model could be:

// sproutcore code

App.Address = App.Base.extend(

street: SC.Record.attr(String, { defaultValue: "" }),

houseNumber: SC.Record.attr(String),

city: SC.Record.toOne('Funda.City')

);

with test data:

Funda.Address.FIXTURES = [

{ guid: "1",

street: "MyHomeStreet",

houseNumber: "34",

city: "6" }

]

Here you see that the reference city has a value of 6. When, at some point in your program, you want to use that reference, it is done by: myAddress.Get("city").MyCityName

So, Sproutcore automatically uses the supplied ID in a REST Get, and retrieves the needed record. If the record is available in de local memory of the client (previously loaded), then no round trip is made to the server, otherwise a http get is done for that ID : "http://servername/city/6". Very nice.

Nhibernate (mapped using fluent-nhibernate):

public AddressMap() { Schema(Config.ConfigElement("nh_default_schema", "Funda"));

        Not.LazyLoad();

        //Cache.ReadWrite();

        Id(x => x.guid).Unique().GeneratedBy.Identity();  

        Table("Address");

        Map(x => x.street);

        Map(x => x.houseNumber);

        References(x => x.city,   

"cityID").LazyLoad().ForeignKey("fk_Address_cityID_City_guid");
}

Here i specified the foreign key, and to map "cityID" on the database table. It works ok. BUT (and these are my questions for the guru's):

  1. You can specify to lazy load / eager load a reference (city). Off course you do not want to eager load all your references. SO generally your tied to lazy loading. But when Openrast (or WCF or ...) serializes such an object, it iterates the properties, which causes all the get's of the properties to be fired, which causes all of the references to be lazy loaded.

SO if your entity has 5 references, 1 query for the base object, and 5 for the references will be done. You might better be off with eager loading then .... This sucks... Or am i wrong?

  1. As i showed how the model inside sproutcore works, i only want the ID's of the references. So i Don't want eagerloading, and also not lazy loading. just a "Get * from Address where ID = %" and get that mapped to my Address entity. THen i also have the ID's of the references which pleases Sproutcore and me (no loading of unneeded references). But.... can NHibernate map the ID's of the references only? And can i later indicate nHibernate to fully load the reference?

One approach could be (but is not a nice one) to load all reference EAGER (with join) (what a waste of resources.. i know) and in my Sever-side Address entity:

    // Note: NOT mapped as Datamember, is NOT serialized!

    public virtual City city { get; set; }

    Int32 _cityID;
    [Datamember]
    public virtual Int32 cityID
    {
        get
        {
            if (city != null)
                return city .guid;
            else
                return _cityID;
        }
        set
        {
            if (city!= null && city.guid != value)
            {
                city= null;
                _cityID = value;
            }
            else if (city == null)
            {
                _cityID = value;
            }
        }
    }

So i get my ID property for Sproutcore, but on the downside all references are loaded. A better idea for me???

  1. nHibernate-to-linq

3a. I want to get my address without their references (but preferably with their id's)

Dao myDao = new Dao(); from p in myDao.All() select p;

If cities are lazy loading in my mapping, how can i specify in the linq query that i want it also to include my city id only?

3b.

I want to get addresses with my cities loaded in 1 query: (which are mapped as lazyloaded)

Dao myDao = new Dao(); from p in myDao.All() join p.city ??????? select p;

  1. My Main Question: As argued earlier, with lazy loading, all references are lazy loaded when serializing entities. How can I prevent this, and only get ID's of references in a more efficient way?

Thank you very much for reading, and hopefully you can help me and others with the same questions. Kind regards.

Upvotes: 2

Views: 1112

Answers (1)

hvgotcodes
hvgotcodes

Reputation: 120198

as a note you wrote you do this

myAddress.Get("city").MyCityName

when it should be

myAddress.get("city").get("MyCityName")

or

myAddress.getPath("city.MyCityName")

With that out of the way, I think your question is "How do I not load the city object until I want to?".

Assuming you are using datasources, you need to manage in your datasource when you request the city object. So in retrieveRecord in your datasource simply don't fire the request, and call dataSourceDidComplete with the appropriate arguments (look in the datasource.js file) so the city record is not in the BUSY state. You are basically telling the store the record was loaded, but you pass an empty hash, so the record has no data.

Of course the problem with this is at some point you will need to retrieve the record. You could define a global like App.WANTS_CITY and in retrieveRecords only do the retrieve when you want the city. You need to manage the value of that trigger; statecharts are a good place to do this.

Another part of your question was "How do I load a bunch of records at once, instead of one request for each record?"

Note on the datasource there is a method retrieveRecords. You can define your own implementation to this method, which would allow you to fetch any records you want -- that avoids N requests for N child records -- you can do them all in one request.

Finally, personally, I tend to write an API layer with methods like

getAddress and getCity

and invoke my API appropriately, when I actually want the objects. Part of this approach is I have a very light datasource -- I basically bail out of all the create/update/fetch methods depending on what my API layer handles. I use the pushRetrieve and related methods to update the store.

I do this because the store uses in datasources in a very rigid way. I like more flexibility; not all server APIs work in the same way.

Upvotes: 0

Related Questions