nhibernate - disable automatic\lazy loading of child records for one to many relationsihps - nhibernate

I would like to know if there is a way to disable automatic loading of child records in nHibernate ( for one:many relationships ).
We can easily switch off lazy loading on properties but what I want is to disable any kind of automatic loading ( lazy and non lazy both ). I only want to load data via query ( i.e. HQL or Criteria )
I would still like to define the relationship between parent child records in the mapping file to facilitate HQL and be able to join parent child entities, but I do not want the child records to be loaded as part of the parent record unless a query on the parent record
explicitly states that ( via eager fetch, etc ).
Example:
Fetching Department record from the database should not fetch all employee records from the database because it may never be needed.
One option here is to set the Employees collection on Department as lazy load. The problem with this approach is that once the object is given to the calling API it can 'touch' the lazy load property and that will fetch the entire list from the db.
I tried to use 'evict' - to disconnect the object but it does not seem to be working at all times and does not do a deep evict on the object.
Plus it abstracts the lazy loaded property type with a proxy class that plays havoc later in the code where we are trying to operate on the object via reflection and it encounters unexpended type on the object.
I am a beginner to nHibernate, any pointers or help would be of great help.

Given your request, you could simply not map from Department to Employees, nor have an Employees property on your department. This would mean you always have to make a database hit to find the employees of a database.
Aplogies if these code examples don't work out of the box, I'm not near a compiler at the moment
So, your department class might look like:
public class Department
{
public int Id { get; protected set; }
public string Name { get; set; }
/* Equality and GetHashCode here */
}
and your Employee would look like:
public class Employee
{
public int Id { get; protected set; }
public Name Name { get; set; }
public Department Department { get; set; }
/* Equality and GetHashCode here */
}
Any time you wanted to find Employees for a department, you've have to call:
/*...*/
session.CreateCriteria(typeof(Employee))
.Add(Restrictions.Eq("Department", department)
.List<Employee>();
Simply because your spec says "Departments have many Employees", doesn't mean you have to map it as a bi-directional association. If you can keep your associated uni-directional, you can really get your data-access to fly too.
Google "Domain Driven Design" Aggregate, or see Page 125 of Eric Evan's book on Domain Driven Design for more information

You can have the lazy attribute on the collection. In your example, Department has n employees, if lazy is enabled, the employees will not be loaded by default when you load a department : http://www.nhforge.org/doc/nh/en/#collections-lazy
You can have queries that explicitly load department AND employees together. It's the "fetch" option : http://www.nhforge.org/doc/nh/en/#performance-fetching-lazy

Related

Is it possible to use NHibernate Filters to filter through references?

Contrived example, but let's say I have a these entities:
public class Root
{
public virtual Customer Customer { get; set; }
}
public class Customer
{
public virtual CustomerData Data { get; set; }
}
public class CustomerData
{
public virtual string FooName { get; set; }
}
Now, let's say I want to create a filter for Root based on the value of FooName. Intuitively, I tried this in my FooMap class. Using Fluent mappings.
ApplyFilter("FooNameFilter", "Customer.Data.FooName in (:argument)");
This doesn't work. A SqlClient.SqlException is thrown stating The multi-part identifier "Customer.Data.FooName" could not be bound.
Is there a way to make filters work this way, or am I forced to move that logic into all Query<Root>()s instead?
What could be working, is to move the filter to the CustomerData object if possible, or to create "more sophisticated SQL condition" applied on the Customer mapping. But it is about pure SQL, no references. How do the filters work?
The filters are the same as the where clause, but could be adjusted in a runtime. The extract from documentation 18.1. NHibernate filters
NHibernate adds the ability to pre-define filter criteria and attach
those filters at both a class and a collection level. A filter
criteria is the ability to define a restriction clause very similiar
to the existing "where" attribute available on the class and various
collection elements. Except these filter conditions can be
parameterized. The application can then make the decision at runtime
whether given filters should be enabled and what their parameter
values should be. Filters can be used like database views, but
parameterized inside the application.
The definition of the where:
where (optional) specify an arbitrary SQL WHERE condition to be used when retrieving objects of this class
Other words, these settings act as "add on" to our mapping. They are extending it (both where and filter) with more SQL balast. The filter could be shared among many mappings and applied to all queries inside one session, but it must target the column:
condition=":myFilterParam = MY_FILTERED_COLUMN"

Eager loading an optional one-to-one with NHibernate

Consider the following simplified domain:
public class Movie
{
public virtual int Id { get; set; }
public virtual MovieDetail MovieDetail { get; set; }
}
public class MovieDetail
{
public virtual int Id { get; set; }
public virtual Movie Movie { get; set; }
}
A MovieDetail cannot exist without a Movie, but a Movie could exist without a MovieDetail (i.e. we have no details about it).
Our database has a separate table for Movie with columns Id, and a separate table for MovieDetail with columns Id and MovieId. There is also a foreign key from MovieDetail.MovieId to Movie.Id.
We've got this all mapped in NHibernate, but when getting a collection of Movie instances, we want a left outer join with MovieDetail. If not, we could have a N+1 problem when iterating over the Movie instances. That is the case now: there is a separate query for every call to the Movie.MovieDetail property.
I've tried one-to-one mapping, but that seems to be for the case when you have both instances. In our case, we don't always have a MovieDetail. Also, they don't share the same primary key.
I've researched formula's, but that would require me to make my MovieDetail implement IUserType, essentially putting NHibernate into my domain. I'd like to avoid that.
Maybe you could try adding a many-to-one relation in the Movie mapping to MovieDetail, it will act as a one to one mapping.
When you set the option 'not-null' to "false" it is also nullable I suppose.
I don't know if you are lazy loading or not, when this is so the MovieDetailis loaded when needed and not by a left join construction.
Shouldn't all the properties be virtual in both classes?
<many-to-one name="MovieDetail" column="Id" class="MovieDetail" not-null="false" lazy="false"/>
I'm in a bit of a hurry and I don't know if you can modify your domain / db schema but you might want to try and take a look at http://ayende.com/blog/3937/nhibernate-mapping-component.
It seems to me that a Movie can have at most one MovieDetail which might not be there. MovieDetail might have properties like Description, ReleaseDate, Actors, etc. I don't really understand why you separated these concepts. By bringing them together you would have 1 less table and 1 less FK to join on each time you want to list movies.
The component allows you to isolate your data into a separate entity while mapping to the same table as Movie.

Simple relation between two tables

I started using NHibernate today, but I cannot figure out how I setup a simple relation between two tables. I don't really know what it's called, it could be one-to-many or foreign key relation (I'm not that into database design and the terms used), but here's a very simple example.
I have a table Product with attributes Id (PK), ProductName and CategoryId. Then I have a table Categories with attributes Id (PK) and CategoryName.
I created these classes:
public class Product
{
public virtual int Id { get; set; }
public virtual string ProductName { get; set; }
public virtual int CategoryId { get; set; }
public virtual Category Category { get; set; }
public virtual string CategoryName
{
get { return this.Category == null ? String.Empty : this.Category.CategoryName; }
}
}
public class Category
{
public virtual int Id { get; set; }
public virtual string CategoryName { get; set; }
}
In other words, I simply want the Product to store to which category it belongs (via the CategoryId attribute which points to an Id in the Categories table). I don't need the Category class to hold a list of related Products, if that makes it any simpler.
To make it even more clear what I'm after, this is the SQL that I'm expecting:
SELECT Products.*, Categories.*
FROM Products INNER JOIN Categories ON Products.CategoryId = Categories.Id
at least that's what I think it should be (again, I'm not that good at database design or queries).
I can't figure out which kind of mapping I need for this. I suppose I need to map it in the Product.hbm.xml file. But do I map the CategoryId as well? And how do I map the Category property?
It seems like I would need a 'one-to-many' relation since I have ONE category per product (or is this reasoning backward?) but it seems like there is no one-to-many mapping...
Thanks for any help!
Addition:
I tried to add the many-to-one relation in the Person mapping, but I keep getting an exception saying "Creating proxy failed", and in the inner exception "Ambiguous match found".
I should maybe mention I am using an old version of NHibernate (1.2 I think) because that is the only one I got running with MS Access due to it not finding the JetDriver in newer versions.
I've put the mapping files, classes, and code where the error occurs in screenshots because I can't figure out how to post XML code here... It keeps reading it as html tags and skipping half of it. Anyway.
The mappings:
http://www.nickthissen.nl/Images/tmp7B5A.png
The classes:
http://www.nickthissen.nl/Images/tmpF809.png
The loading code where the error occurs:
http://www.nickthissen.nl/Images/tmp46B6.png
(As I said, the inner exception says "Ambiguous match found".
(Product in my example has been replaced by Person)
The Person and Category classes inherit Entity which is an abstract base class and defines the Id, Deleted, CreatedTime and UpdatedTime properties.
The code where the error occurs is in a generic 'manager' class (type parameter TEntity which must inherit Entity). It is simply supposed to load all entities with the Deleted attribute false. In this case, TEntity is 'Person'.
It works fine if I leave out the many-to-one Category mapping in the Person mapping, but then obviously the Category property is always null.
Oh yeah, sorry about the mix between C# and VB, the C# code is in a generic framework I use for multiple projects while the VB part is the actual implementation of that framework on my website and I just happened to use VB for that.
Help? Thanks!
In your Product class only needs to contain a Category object, you don't need a CategoryId property. Then in your Product mapping you need to have this entry
<many-to-one name="Category" column="CategoryId" />
UPDATE:
Your mappings appear to be missing the fully qualified name of the mapped class in the tag. See http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-class
UPDATE 2:
See if this helps you NHibernate 1.2 in a .NET 4.0 solution
The 'Ambiguous match found' exception was caused by the project targeting .NET Framework 4, which does not seem to be compatible with NHibernate 1.2.1. I switched to 3.5 and that seems to solve that particular issue.
Now on to the next. As you can see, the Person class has a CategoryName property that should return the name of the current Category object, or an empty string if the category happens to be null. This is so I can databind a collection of Person objects to a grid, specifying 'CategoryName' as a property to bind a column to.
Apparently this does not work with NHibernate. Whenever I try to databind my collection of persons, I get this exception:
"Property accessor 'CategoryName' on object 'NHibernateWebTest.Database.Person' threw the following exception:'Could not initialize proxy - the owning Session was closed.'"
This occurs on the 'DataBind' method call in this code:
public virtual void LoadGrid()
{
if (this.Grid == null) return;
this.Grid.DataSource = this.Manager.Load();
this.Grid.DataBind();
}
(This is an ASP.NET project and 'Grid' is a GridView)
'this.Manager' returns an existing instance of NHibernateEntityManager, and I've already shown its Load method before, it contains this:
public virtual EntityCollection Load()
{
using (ISession session = this.GetSession())
{
var entities = session
.CreateCriteria(typeof (TEntity))
.Add(Expression.Eq("Deleted", false))
.List();
return new EntityCollection(entities);
}
}
(THere's some generic type parameters in there but this website seems to hide them (due to the html like tags I guess)... Sorry about that).
This may have something to do with NHibernate itself, as I said I'm completely new to this. When I call my Load method I would expect it to return an EntityCollection(Of Person) with all its properties already set. It seems I have to keep the ISession open while I am databinding for some reason..? That seems a little strange...
Can I get around this? Can I make my Load method simply return a collection of persons already fully loaded, so that I can access CategoryName whenever I want?
Wait... Is this lazy loading perhaps?

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):
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?
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???
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;
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.
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.

Fluent NHibernate Architecture Question

I have a question that I may be over thinking at this point but here goes...
I have 2 classes Users and Groups. Users and groups have a many to many relationship and I was thinking that the join table group_users I wanted to have an IsAuthorized property (because some groups are private -- users will need authorization).
Would you recommend creating a class for the join table as well as the User and Groups table? Currently my classes look like this.
public class Groups
{
public Groups()
{
members = new List<Person>();
}
...
public virtual IList<Person> members { get; set; }
}
public class User
{
public User()
{
groups = new Groups()
}
...
public virtual IList<Groups> groups{ get; set; }
}
My mapping is like the following in both classes (I'm only showing the one in the users mapping but they are very similar):
HasManyToMany<Groups>(x => x.Groups)
.WithTableName("GroupMembers")
.WithParentKeyColumn("UserID")
.WithChildKeyColumn("GroupID")
.Cascade.SaveUpdate();
Should I write a class for the join table that looks like this?
public class GroupMembers
{
public virtual string GroupID { get; set; }
public virtual string PersonID { get; set; }
public virtual bool WaitingForAccept { get; set; }
}
I would really like to be able to adjust the group membership status and I guess I'm trying to think of the best way to go about this.
I generally only like to create classes that represent actual business entities. In this case I don't think 'groupmembers' represents anything of value in your code. To me the ORM should map the database to your business objects. This means that your classes don't have to exactly mirror the database layout.
Also I suspect that by implementing GroupMembers, you will end up with some nasty collections in both your user and group classes. I.E. the group class will have the list of users and also a list of groupmembers which references a user and vice versa for the user class. To me this isn't that clean and will make it harder to maintain and propagate changes to the tables.
I would suggest keeping the join table in the database as you have suggested, and add a List of groups called waitingtoaccept in users and (if it makes sense too) add List of users called waitingtoaccept in groups.
These would then pull their values from your join-table in the database based on the waitingtoaccept flag.
Yes, sure you need another class like UserGroupBridge. Another good side-effect is that you can modify user membership and group members without loading potentially heavy User/Group objects to NHibernate session.
Cheers.