I have two objects - ContentPage, which has a collection of ChildLinks.
ContentPage
-----------
ID
Title
ChildLink
----------
ID
ParentPageID [ContentPage]
ChildPageID [ContentPage]
Priority
The ContentPage.ChildLinks property utilises the 2nd level cache. I am using Fluent NH to configure Nhibernate, and using Nhibernate 3.1. Cache is set as 'Read-Write' both for the collection, and the 'ChildLink' class.
I've noticed that whenever I delete a ChildLink, the collection cache is not being invalidated. Thus, when I call the ContentPage.ChildLinks, I get an error:
no row with the given identifier exists
I've turned off the cache, and it works well. Shouldn't the cache be automatically invalidated? I am using SysCache as the cache provider, and MySQL as the database.
Thanks in advance!
I had the same problem and I can across the following article which solved my problem:
Inverse Mapped Collections and NHibernate's Second-Level Cache
Basically if you have mapped your collections as inverse, when you delete the child item you also have to make sure to explicitly remove it from the parent collection or the cache state will be invalid after you delete the child. The first thing to check is if the relationship really needs to be inverse.
Assuming inverse is necessary or desired, and using your example:
Instead of only something like:
Session.Delete(ChildLink);
You have to do:
ContentPage.ChildLinks.Remove(ChildLink);
ChildLink.ParentPage = null;
Session.Delete(ChildLink);
You also might need to explicitly save your ContentPage object at this point as well, it depends on your Session flush settings.
I use methods on my entities for managing such inverse relationships, for example:
public ChildLink
{
public ContentPage ParentPage {get;set;}
public void AddToPage(ContentPage addTo)
{
addTo.ChildLinks.Add(this);
this.ParentPage = addTo;
}
public void RemoveFromPage()
{
ParentPage.ChildLinks.Remove(this);
this.ParentPage = null;
}
}
And then when deleting a child object:
ChildLink.RemoveFromPage();
Session.Delete(ChildLink);
Related
Considering the simplified class below, lets assume:
that the parent can have a relatively large amount of children (e.g. 1000)
the child collection is lazy loaded
we have loaded one parent via it's Id from a standard Get method of a ParentRepository, and are now going to read the OldestChild property
class Parent
{
public IList<Child> Children { get; set; }
public Child OldestChild
{
get { return Children.OrderByDescending(c => c.Age).FirstOrDefault();
}
}
When using NHibernate and Repositories, is there some best practice approach to satisfy both:
a) Should select oldest child through the aggregate root (Parent) - [ie. without querying the children table independently via e.g. a ChildRepository using the Parent Id]
b) Should avoid loading the whole child collection into memory (ideally the oldest child query should be processed by the DB)
This seems something that should be both possible and easy, but I don't see an obvious way of achieving it. Probably I am missing something?
I'm using NHibernate 2.1, so a solution for that would be great, although will be upgrading to 3 soon.
I would create a specialized method on your repository, which returns the oldest child of a given parent.
You could map OldestChild using a Formula. Take a look at this to map a class to a formula: http://blog.khedan.com/2009/01/eager-loading-from-formula-in.html
I couldn't find an answer to this issue so I assume it is something I am doing wrong.
I have a PersistenceModel set up where I have set a convention as follows: -
persistenceModel.Conventions.Add(DefaultLazy.Always());
However, for one of the HasManyToMany relationships in one of my entities I want eager loading to take place which I am setting up as follows: -
HasManyToMany(x => x.Affiliates).Not.LazyLoad();
Intuitively, I expect eager loading to take place as I am overriding the lazy load default that I have specified as a convention but it still lazy loads. If I set the DefaultLazy convention to never and then set LazyLoad on an individual relationship it doesn't work either.
Any ideas?
When you set Not.LazyLoad(), you tell NHibernate to load Affiliates when the parent loads. NHibernate will do this by performing another select on the Affliates many-to-many table regardless of whether you access the Affiliates collection or not. NHibernate is using another select because that is the default fetching mode. You want to override fetching mode as well, either in the query or in the mapping. To do it in the mapping, add the following:
HasManyToMany(x => x.Affiliates)
.Not.LazyLoad()
.Fetch.Join();
You might also want to include a ".Cascade.AllDeleteOrphan()" if you want NHibernate to persist new Affiliaites added to the collection and delete orphaned ones. If you do not do this, you will have to explicitly call session.Save(newAffiliate). Otherwise you'll receive a TransientObjectException when your Affiliates collection contains a new Affiliate.
It may be one stupid thing to ask, but have you execute the query inside your session? Say,
Using(var session = OpenSession())
{
session.Query<Entity>().ToList();
}
I had this problem before, and finally realized the objects that I was accessing hadn't been queried before disposing the session.
public Parent GetByName(string Name)
{
return _session.CreateCriteria<Parent>()
.Add(Restrictions.Eq("Name", Name))
.SetFetchMode("Children", FetchMode.Eager)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.UniqueResult<Parent>();
}
public ParentDetailVM GetMeAParent(string Name)
{
Parent parent;
using (var tx = _session.BeginTransaction())
{
//This works well, one single query loading
//both parent and children
parent = _parentRepository.GetByName(Name);
//If I include this as suggested by NHProfiler
//it all of the sudden sends a new query for each child
//and a query for the grandchildren collection
tx.Commit();
}
return Mapper.Map<Parent, ParentDetailVM>(parent);
}
I have checked to make sure that nothing in the mapping files has been set to eager load. I can't figure out why it works if I leave off the transaction commit but otherwise it issues N more queries. Anyone know why this might be happening?
If you examine _session.IsDirty() before committing the transaction my bet is that it will return true. When the transaction is committed the session is flushed and, for some reason, the child objects are loaded to cascade the change.
This is a problem known as "ghosting" or phantom updates. A typical scenario is that a database column is a nullable int but the corresponding object property is non-nullable. When a record with a null value is retrieved, NHibernate sets the property value to 0 and the object is therefore dirty.
The quickest way to troubleshoot this is to turn on dynamic-update for the object using dynamic-update="true" in XML mappings, DynamicUpdate() in fluent, and use a profiler or logging to see which columns are being updated after the select. There's also a utility called Ghostbuster that you can include in unit tests.
I have som entities and now want to make some DTO´s based on there entities using nhibernate.
I have a Service - Allocation -Ressource where allocation describes how the ressource is allocated for the service.
I want a DTO like
ServiceDTO
-Name
-RessourceDTO
where RessourceDTO also has a name.
In the examples I have see for NHibernate projection/DTO you either use properties or constructor. If I use The Constructor approach I would have something like
ServiceDTO(Name, List
But I can't figure out how to make this work.
Another approach is to extract all the services and then loop through them and hit the database each time, or extract a larger result and then make the DTO's
What is the best approach? I going to hide all of this inside a repository.
How about
public ServiceDTO GetDTOFor(int Id);
{
var service = Session.CreateCriteria<Service>()
.Add(Restrictions.Eq("Id", id)
.SetFetchMode("Resources", fetchmode.eager) // eager load resources
.uniqueResult<Service>();
return new ServiceDTO(service.Name, service.Resources.ToList()) // Copy the Resources
}
I ve got the following setup:
public class ParentEntity
{
public ICollection<ChildEntity> {get; set; }
}
public class ChildEntity
{
// do i need to the parent here?
}
I managed to save the ParentEntity and cascaded the save to the added child entities which were saved as well. But in the db table the ParentId reference of the child was set to allow NULL. When setting it to NOT NULL the save failes since the ParentId in the child table is NULL.
What's happening there? ;)
When
You should map both sides of the relationship normally, and when you add a child to the parent's collection, you should also set the parent property on the child. Normally you would achieve this by writing a method like this:
public void AddChild(ChildEntity child)
{
this.Children.Add(child);
child.Parent = this;
}
NHibernate persists the ParentId column in the Child table based on the mapped property in the ChildEntity class. The definition of the one-to-many relationship merely allows NHibernate to load the collection from the database based on values in this column
I am having the same issue and need this to either have nHibernate expose the foreign key column, or do it in class via collection.
Problem: nHibernate creates the collection object (IList, for example) and you can not override the or listen to the add events of basic collections.
This becomes an issue only because it is required by the WCF RIA Services framework.