Fluent Nhibernate - Is it possible to get more than one related entities of an entity? - fluent-nhibernate

Is it possible to get more than one related entities of an entity? Say for example I have a class Album and it has two properties namely Artist and Genre.... How can I get an Album with its related artist and genre? Thanks in advance :p

as simple as
var albums = session.Query<Album>()
.Where(a => <whatever>)
.Fetch(a => a.Artist)
.Fetch(a => a.Genre)
.ToList();

Related

NHibernate not inserting child entities in one-to-many

I have Customer and Profile classes, where one Customer can have many Profiles.
I am using following NHibernate override classes with them:
public void Override(AutoMapping<Customer> mapping)
{
mapping.Table("[Customer]");
mapping.Id(x => x.Id, "Id").GeneratedBy.Identity();
mapping.HasMany(x => x.Profiles).Cascade.All().Inverse();
mapping.Map(x => x.FirstName, "FirstName");
mapping.Map(x => x.LastName, "LastName");
mapping.Map(x => x.Email, "Email");
}
public void Override(AutoMapping<Profile> mapping)
{
mapping.Table("[Profile]");
mapping.Id(x => x.Id, "Id").GeneratedBy.Identity();
mapping.References(x => x.Customer, "Customer_Id").Cascade.None();
mapping.Map(x => x.FacebookProfileLink, "FacebookProfileLink");
mapping.Map(x => x.ContactPhone, "ContactPhone");
}
I am getting following error while inserting Profile object:
Cannot insert the value NULL into column 'Customer_Id', table 'dbo.Profile'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated.
My intence is to insert Customer object before Profile that needs a reference to Customer
object. That's why I'm using Inverse attribute. Unfortunately it doesn't work. Any help on this ? Thank you.
One thing that NHibernate does as a good ORM is to save everything in the relationships so you don't have to save things separately. I think your issue might but in what you are doing when you say 'insert Customer object before Profile that needs a reference to Customer'.
The reality is that you should create the customer, with the profiles needed to be associated to it, and then just save the customer. NHibernate will save all the entities in the right order to make sure the relationships are preserved. Try doing that, first create or retrieve the customer entity, then add/remove the profiles, and then save the customer. Profiles would be saved because of the cascade option you have specified in the mapping.
Hope that helps!
I found out solution that works for me.
I am saving Customer entity without reference to it's Profiles. Afterwards I'm saving Profile entity.
Works for me even better than solution i wanted to achieve before, as I can check on success of Customer insert and then decide what to do next (save Profile as well or do some validation error).
Thank you all for your answers.

Kohana 3.x ORM has_many through delete relationship

I Have three tables, contact, list and listmembers. Contacts from contact table are associated to lists from list table via listmembers table.
class Model_Contact extends ORM{
protected $_has_many = array(
'lists'=>array('model'=>'List', 'through'=>'listmembers', 'far_key'=>'dlid', 'foreign_key'=>'uid')
);
}
class Model_List extends ORM
{
protected $_has_many = array(
'contacts'=>array('model'=>'Contact', 'through'=>'listmembers', 'far_key'=>'uid', 'foreign_key'=>'dlid')
);
}
I have to update contact and list relationship in listmemebers table
- create new relationship between existing contact and existing list
- Remove relationship between contact and list
How can I achieve this in Kohana ORM? I can always create model for listmembers and directly add/delete on this model. But is there a way to handle via relationship without creating listmembers model?
I think the documentation explains it quite well: http://kohanaframework.org/3.2/guide/orm/relationships#hasmany-through

Fluent NHibernate - How do I create a one to many mapping which has a bridge table in the middle?

How do I create a one to many mapping which has a bridge table in the middle?
I basically have 3 tables: Items, Tags, and TagsToItems.
Each Item can have many Tags as defined by the TagsToItems table. How do I set up this mapping correctly using Fluent NHibernate?
I've been playing with HasMany but haven't quite figured out how this works with a bridge table.
HasMany(x => x.Tags).Table("TagsToItems").KeyColumn("ItemId");
My latest attempt to solve this problem looks like this:
HasManyToMany(x => x.Tags)
.AsBag()
.Table("TagsToItems")
.ParentKeyColumn("ItemId")
.ChildKeyColumn("TagId")
.Cascade.All()
.Inverse();
However this is throwing the error:
Initializing[Namespace.Item#11]-failed to lazily initialize a
collection of role:
Namespace.DataAccess.NHibernate.Entities.Item.Tags, no session or
session was closed
It turns out that the problem is with using the Tags collection associated to an Item.
The Tags collection could not be lazily initialised because by the time I was trying to use it (in my view) the session scope of the NHibernate session had closed.
I solved this by setting .Not.LazyLoad() on the mapping:
HasManyToMany(x => x.Tags)
.AsBag()
.Table("TagsToItems")
.ParentKeyColumn("ItemId")
.ChildKeyColumn("TagId")
.Not.LazyLoad()
.Cascade.All();

How to Delete in a many to many relationship?

I have a many to many relationship:
Product has many Categories and Category has Many Products.
Say I have
Shopping Category
Food Category
Product A - Shopping Category, Food Category
Product B - Shopping Category
Now I delete Shopping Category. I want the Product A reference to be removed from Shopping Category and I want Product B to be removed completely.
I would end up with:
Product A - Food Category.
How do I do this in nhibernate (I am using fluent nhibernate).
I tried to use Cascade DeleteOrphan and AllDeleteOrphan but when I do that and delete Shopping both Product A and B get deleted.
public class CategoryMapping : ClassMap<Category>
{
public CategoryMapping()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Name).Not.Nullable().NvarcharWithMaxSize();
HasManyToMany(x => x.Products).Cascade.DeleteOrphan();
}
}
public class ProductMapping : ClassMap<Product>
{
public ProductMapping()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Name).Not.Nullable().NvarcharWithMaxSize();
HasManyToMany(x => x.Categories);
}
}
unitOfWork.BeginTransaction();
Category category =session.Load<Category>(id);
session.Delete(category);
unitOfWork.Commit();
I don't think this can be handled by mapping with existing data structure. I think you would need to write some manual code (*) or change data structure.
(*) Not 100% sure it works though...
unitOfWork.BeginTransaction();
Category category =session.Load<Category>(id);
var productsDel = category.Products.Where(p => p.Categories.Count == 1);
productsDel.ForEach(p => session.Delete(p));
session.Delete(category);
unitOfWork.Commit();
Other:
I'm also thinking about adding mapping for your cross-ref tables. Then you should be able to configure mapping so it will delete only records from that cross-ref table. You will need to verify if there are products without references and delete them periodically. (some periodic clean-up code, like running some stored procedure). I know this solutions smells bad :) There are still triggers and other SQL Server stuff... not good solutions anyway, but solutions.
If you just want to remove the association between the two use Cascade.SaveUpdate()
Then just remove the entity from the collection and commit the transaction if you are using transactions if not you will need to do a Session.Flush

Load collections eagerly in NHibernate using Criteria API

I have an entity A which HasMany entities B and entities C. All entities A, B and C have some references x,y and z which should be loaded eagerly.
I want to read from the database all entities A, and load the collections of B and C eagerly using criteria API.
So far, I am able to fetch the references in 'A' eagerly. But when the collections are loaded, the references within them are lazily loaded.
Here is how I do it
AllEntities_A =
_session.CreateCriteria(typeof(A))
.SetFetchMode("x", FetchMode.Eager)
.SetFetchMode("y", FetchMode.Eager)
.List<A>().AsQueryable();
The mapping of entity A using Fluent is as shown below. _B and _C are private ILists for B & C respectively in A.
Id(c => c.SystemId);
Version(c => c.Version);
References(c => c.x).Cascade.All();
References(c => c.y).Cascade.All();
HasMany<B>(Reveal.Property<A>("_B"))
.AsBag()
.Cascade.AllDeleteOrphan()
.Not.LazyLoad()
.Inverse()
.Cache.ReadWrite().IncludeAll();
HasMany<C>(Reveal.Property<A>("_C"))
.AsBag()
.Cascade.AllDeleteOrphan()
.LazyLoad()
.Inverse()
.Cache.ReadWrite().IncludeAll();
I don't want to make changes to the mapping file, and would like to load the entire entity A eagerly. i.e. I should get a List of A's where there will be List of B's and C's whose reference properties will also be loaded eagerly
You're trying to do a cartesian product here. I think NHibernate requires mapping the relations as sets instead of bags to do that, since bags allow duplicates.
Anyway, cartesian products are very inefficient. Use a multi-query or future queries instead.
See:
Nhibernate: eager loading two child collections (one being a component list)
https://nhibernate.jira.com/browse/NH-1471
http://nhibernate.info/blog/2008/09/06/eager-loading-aggregate-with-many-child-collections.html
http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx