NHibernate create object from only collection of children - nhibernate

I have a table logging web page hits. Something like: {VisitId, VisitorId, Url, Date}
(The visitor ID is a GUID stored in a cookie)
I would like to create a Visitor object that has a collection of Visit objects.
class Visitor {
public virtual Guid VisitorId { get; set; }
public virtual IList<Visit> Visits { get; set; }
}
Rather than add another table for Visitor, can NHibernate create this object just from the collection of Visits?
Ideally, I would like to write:
var visitor = session.Get<Visitor>(guidFromCookie)
And then be able to work with the Visits list and persist changes back to the DB.
(I'm using FluentNHibernate and NHibernate 3.0)
I'm new to NHibernate, but it seems the something should be possible using a custom IEntityPersister, or is this too low level and loads of work? Any suggestions would be appreciated.

When you say "create this object", do you mean retrieve? What is your reason for not having a visitor table? You could use the criteria API or hbm to load a list of visits by the guid if you don't want a visitor entity/table.

If you mapped Visitor and made it Lazy Loaded, you might be able to do this. You'd have to tell NHibernate that the table existed, even though it didn't. However, when you want to get the Visitor object (note that the only property mapped is the Id), then instead of using .Get(), use .Load() which will return an uninitialized proxy. So you'll have an entity, but it won't actually hit the database, so it will never know that the table doesn't exist.
public class VisitorMap : ClassMap<Visitor>
{
public VisitorMap()
{
Table("SomeNonExistentTable");
LazyLoad(); // should be the default anyway
Id(x => x.Id)
.GeneratedBy.Guid();
HasMany(x => x.Visits)
.AsList()
.Not.LazyLoad();
}
}
...and then...
var visitor = session.Load<Visitor>(guidFromCookie);
foreach(var visit in visitor.Visits)
{
// do wonderful things
}

Related

Eager load Records in Orchard CMS

I'm building an Orchard CMS module, where I want to eager load data, but can't work out how to do this.
For example a Client has many Events, so I have a ClientRecord & EventRecord for these:
public class ClientRecord {
private IList<EventRecord> _eventRecords;
public virtual int Id { get; set; }
public virtual string Company { get; set; }
public virtual IList<EventRecord> EventRecords {
get { return _eventRecords ?? (_eventRecords = new List<EventRecord>()); }
set { _eventRecords = value; }
}
}
WhenI load a Client in my ClientController
var clientRecord = _clientRepository.Get(id);
and then display the Events in my View
<ul>
#foreach (var eventRecord in Model.EventRecords) {
<li>
#eventRecord.Name (#eventRecord.StartDate.ToShortDateString())
</li>
}
</ul>
the Events are displayed and MiniProfiler shows a separate query to lazy-load the Events.
I've tried putting an [Aggregate] attribute on the EventRecords collection in the ClientRecord, but this didn't have any effect.
I'm not that familiar with NHibernate, so hopefully this is something simple, but how do I specify I want to eager load the EventRecords when the ClientRecord is retrieved?
[EDIT]
In Orchard CMS the NHibernate mappings are created for you, based on the convention that the class is called xxxRecord and there is a database table in place with the same name.
So you don't (as far as I know) have a mapping file that you can specify this in. If I'm right about that, then the question is whether there is any way to specify you want eager loading in the query you use to retrieve the Client (rather like Entity Framework's "include" method).
You must specify eager loading in your nHibernate mapping file, using Fluent nhibernate this would look (something) like this:
HasMany(x => x.EventRecords).KeyColumn("CompanyId").Not.LazyLoad().Fetch.Select();
The Fetch.Select() will execute a second select statement to load all of the related Event records.
The Not.LazyLoad() tells nHibernate to execute this second select immediately, if you remove this execution would be deferred until the collection is accessed.
In response to your comments you can specify eager loading in your query using fetch also (LINQ example shown)
NHSession.Query<ClientRecord>().Fetch(c => c.EventRecords).ToList();

Can NHibernate query for specific children without lazy loading the entire collection?

When I have an entity object with a one-to-many child collection, and I need to query for a specific child object, is there a feature or some clever pattern I haven't come up with yet to avoid that NHibernate fetches the entire child collection?
Example:
class Parent
{
public virtual int Id { get; proteced set; } // generated PK
public virtual IEnumerable<Child> Children { get; proteced set; }
}
class Child
{
public virtual int Id { get; protected set; } // generated PK
public virtual string Name { get; protected set; }
public virtual Parent Parent { get; protected set; }
}
// mapped with Fluent
class Service
{
private readonly ISessionFactory sessionFactory;
public Service(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
void DoSomethingWithChildrenNamedBob(int parentId)
{
using(var session = sessionFactory.OpenSession())
{
var parent = session.Get<Parent>(parentId);
// Will cause lazy fetch of all children!
var childrenNamedBob = parent.Children.Where(c => c.Name == "Bob");
// do something with the children
}
}
}
I know it's not the best example because in this case one would probably just query the Child entities directly, but I have encountered situations where I already had a Parent object and needed to traverse specific sub-trees through it.
Short answer: no. Longer answer: you can make it do this, with some sleight of hand.
Rippo's answer above shows how you would do it the 'proper' NHibernate way (whether it's with Linq or QueryOver or HQL doesn't really matter - the point is you have to step outside the parent -> child relationship to do a query). You can take this a step further and disguise this behind a façade. But to do so, you have to remove the mapped relationship entirely and replace it with a query at all times. You'd take out the Parent -> Children mapping, but leave the Child -> Parent mapping intact; then re-write the property on Parent to look like this:
public virtual IQueryable<Child> Children
{
get
{
// somehow get a reference to the ISession (I use ambient context), then
return session.Query<Child>().Where(c => c.Parent == this);
}
}
Now, when you use Parent.Children you get back a queryable collection, so you could then write
IEnumerable<Child> childrenNamedBob = parent.Children.Where(c => c.Name == "Bob");
The only way you could do this and preserve the mapping is to amend NHibernate's collection objects (or inject your own). Diego Mijelshon (who is around these parts) wrote a spike of exactly that, adding IQueryable support to NHibernate collections so you could do
IEnumerable<Child> childrenNamedBob = parent.Children.AsQueryable().Where(c => c.Name == "Bob");
But from what I can see, this never went any further and there's no apparent plan to add this capability to NH. I have run Diego's code and it does work, but obviously it's not production quality and hasn't been tested, and I don't think it's ever been officially 'released' even as a private patch.
Here's the link to the discussion on the NH issue tracker: https://nhibernate.jira.com/browse/NH-2319
I believe NH should support this out of the box, as it's a natural way for most .NET devs to want to interact with pretty much anything enumerable, now that we have Linq, and not being able to do it without the side-effect of loading an unbounded collection into RAM sucks. But the traditional NH model is session -> query and that's what 99% of people use.
I asked the same question on NHusers a few weeks ago and didn't get an answer so I suspect the answer is you will always get all the parents children and then perform a in-memory filter. In many cases this might be the correct way in seeing it.
In your case I would rewrite the query to be:-
var childrenNamedBob = session.Query<Children>()
.Where(w => w.Parent.Id == parentId && w.Name == "Bob");
Then simply to get parent (if childrenNamedBob has results) you could call:-
var parent = childrenNamedBob.First().Parent;
or as you rightly pointed out:-
var parent = session.Get<Parent>(parentId);
You can now do that with NHibernate 5 directly without specific code !
See https://github.com/nhibernate/nhibernate-core/blob/master/releasenotes.txt
Build 5.0.0
=============================
** Highlights
...
* Entities collections can be queried with .AsQueryable() Linq extension without being fully loaded.
...

Map collection as Queryable

I've grown accustomed in SQLAlchemy (Python) to map a relationship/collection with lazy="dynamic" which maps the property as a Query object instead of a populated list/collection (or Proxy for lazy loaded properties). This mapped property then allows you to further refine the query used to fetch the collection before doing so (apply an order, limit, filter, etc).
For example, in SQLAlchemy I can map a relationship like so:
class Post(Base):
...
class User(Base):
...
posts = relationship(Post, lazy="dynamic")
And then when I retrieve a user, I can apply an order on posts, or only retrieve the last 5, etc.
user = session.query(User).get(1)
# Fetch the last 5 posts by user 1
posts = user.posts.order_by(Post.create_date.desc()).limit(5).all()
http://docs.sqlalchemy.org/en/rel_0_7/orm/collections.html
I would love to find a way to do this using Fluent NHibernate, mapping the collection as a QueryOver or IQueryable (LINQ) such as:
public virtual QueryOver<Post> Posts {get; set;}
or
public virtual IQueryable<Post> Posts { get; set; }
and in the mappings do something like:
public class UserMap : ClassMap<User>
{
public UserMap()
{
...
HasMany(u => u.Posts).Fetch.Dynamic
}
}
Is this currently possible using Fluent NHibernate (or just NHibernate)?
It is possible using NHibernate, however it's not quite out of the box.
You would need to write your own collectionwrapper implementing IQueryable, inject it with your own CollectionFactory and delegate the query generation to the session which loaded the containing object.

How can I model this object hierarchy in Fluent NHibernate without violating DDD principles?

I am trying to build a domain model that will allow me to manage Contracts.
The Contract class is my aggregate root, and it has a single property right now, which is Reviewers.
Reviewers, in the context of the Contract, each have a property to it's parent Contract, and a First Name, Last Name, and Login. The reason they have these properties is so I can have the user select which Reviewers they want on a Contract.
The database that I'm tying my domain model to already exists, and it's a legacy system that I'm trying to extend.
It has a Contract Table, and a Reviewer Table.
The thing I haven't mentioned up until this point, is that Reviewers are actually Users in the system. So there's actually a third table involved, which is Users.
I have been able to map my Contract Table easily with FNH.
It looks something like this:
public class ContractMapping: ClassMap<Contract>
{
public ContractMapping()
{
Id(c => c.Id);
HasMany(c => c.AdditionalReviewers);
}
}
But I'm not sure how to model my Reviewers, because they are in fact Users as well. So my object model looks like this:
public class Reviewer: User
{
public virtual Guid Id { get; set; }
public virtual Contract Contract { get; set; }
}
public class User
{
public virtual Guid Id { get; set; }
public virtual string Login { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
I've been able to map my User class properly, and it looks something like this:
public class UserMapping: ClassMap<User>
{
public UserMapping()
{
Id(u => u.Id);
Map(u => u.Login);
Map(u => u.FirstName);
Map(u => u.LastName);
}
}
and I believe I want to map my Reviewer class like this:
public class ReviewerMapping: SubclassMap<Reviewer>
{
public ReviewerMapping()
{
Table("Reviewer");
//Id(r => r.Id).Column("ReviewerId"); <- won't compile
References(r => r.Contract).Column("ContractId");
}
}
So the problem I'm having is this:
The relationship between the User table and the Reviewer table is one to many. Meaning, for a given User there may be many Reviewer records. Why? Because a User has to be a Reviewer for a specific Contract. This causes an issue with the mapping, though, because the primary key for my Reviewer and the primary key for my User are completely different values, by necessity.
Also, because of the way I'm using Reviewer, when I create a new Reviewer, what I'm really trying to do is to associate a User with a Contract. I am not trying to create an entirely new User in the database.
What is the correct way for me to map Reviewer, knowing that in my domain model it is a subclass of User?
Sounds like a the Reviewer is not really modelling a person, but modelling a role or assignment the User takes on. I'd say your domain model is flawed in this aspect. Tweak Reviewer to be an association class between a User and a Contract.
I don't think Reviewer should inherit from User in the scenario you've described. I would have the Reviewer class hold a User object instead (composition over inheritance).
If it helps you conceptualize it better, rename Reviewer to Review. That way you can stop thinking about it as a User since it really isn't (multiple Reviewers in your current domain can be the same User, which doesn't make much sense).

NHibernate - Do I have to have a class to interface with a table?

I have a class called Entry. This class as a collection of strings called TopicsOfInterest. In my database, TopicsOfInterest is represented by a separate table since it is there is a one-to-many relationship between entries and their topics of interest. I'd like to use nhibernate to populate this collection, but since the table stores very little (only an entry id and a string), I was hoping I could somehow bypass the creation of a class to represent it and all that goes with (mappings, configuration, etc..)
Is this possible, and if so, how? I'm using Fluent Nhibernate, so something specific to that would be even more helpful.
public class Entry
{
private readonly IList<string> topicsOfInterest;
public Entry()
{
topicsOfInterest = new List<string>();
}
public virtual int Id { get; set; }
public virtual IEnumerable<string> TopicsOfInterest
{
get { return topicsOfInterest; }
}
}
public class EntryMapping : ClassMap<Entry>
{
public EntryMapping()
{
Id(entry => entry.Id);
HasMany(entry => entry.TopicsOfInterest)
.Table("TableName")
.AsList()
.Element("ColumnName")
.Cascade.All()
.Access.CamelCaseField();
}
}
I had a similar requirement to map a collection of floats.
I'm using Automapping to generate my entire relational model - you imply that you already have some tables, so this may not apply, unless you choose to switch to an Automapping approach.
Turns out that NHibernate will NOT Automap collections of basic types - you need an override.
See my answer to my own question How do you automap List or float[] with Fluent NHibernate?.
I've provided a lot of sample code - you should be able to substitute "string" for "float", and get it working. Note the gotchas in the explanatory text.