Can someone better explain what 'Projections' are in nHibernate?
Asked Answered
D

3

31

As a new user of nHibernate and its utility library, fluent nhibernate, I am trying to learn enough to be dangerous with a good database.

I am having an exceptionally great deal of difficulty understanding the concept of Projections. Specifically, What in the world are they?

I have literally done exact searches on 'What are projections?' and 'Projects in nHibernate' and 'nHibernate, Projections, Definition', etc. And I am still very confused. The most helpful posts so far are This other StackOverflow Question and This Blog Post by Colin Ramsay. But I am still vastly confused. My knowledge of databases is still entry-level at best.

I do not really understand what projections are, why I would want to use them, what they are accomplishing, etc. I see in the blog post that he is using them to get a list of integers (I presume Primary Keys) so that he can use them in a different query, but this is kind of nebulous in the way it is functioning and the why.

Dougald answered 26/5, 2011 at 14:37 Comment(0)
K
78

Here's a practical example.

Let's say that you have an online store and one of your domain classes is a Brand like "Samsung". This class has a boatload of properties associated with it, perhaps an integer Identity, a Name, a free-text Description field, a reference to a Vendor object, and so on.

Now let's say that you want to display a menu with a list of all the brands offered on your online store. If you just do session.CreateCriteria<Brand>().List(), then you are indeed going to get all of the brands. But you'll also have sucked all of the long Description fields and references to Vendors from the database, and you don't need that to display a menu; you just need the Name and the Identity. Performance-wise, sucking all of this extra data down from the database slows things down and is unnecessary.

Instead, you can create a "projection" object that contains just the Identity and the Name calling it, say, NameIdentityPair:

public class NameIdentityPair
{
    public int Identity { get; set; }
    public string Name { get; set; }
}

And you could tell NHibernate to only select the data that you really need to perform the task at hand by telling it to transform the result set onto your projection:

var brandProjections = this.session.CreateCriteria<Brand>()
    .SetProjection(Projections.ProjectionList()
        .Add(Projections.Property("Name"), "Name")
        .Add(Projections.Property("Identity"), "Identity"))
    .SetResultTransformer(Transformers.AliasToBean<NameIdentityPair>())
    .List<NameIdentityPair>();

foreach (var brandProjection in brandProjections)
{
    Console.WriteLine(
        "Identity: {0}, Name: {1}", 
        brandProjection.Identity, 
        brandProjection.Name);
}

Now you don't have a list of Brands but instead a list of NameIdentityPairs, and NHibernate will have only issued a SQL statement like SELECT b.Identity, b.Name from dbo.Brand b to obtain this projection, as opposed to a massive SQL statement that grabs everything necessary to hydrate a Brand object (e.g., SELECT b.Identity, b.Name, b.Description from dbo.brand b left join dbo.vendor v ....).

Hope this helps.

Keelin answered 26/5, 2011 at 15:11 Comment(3)
So projections are like query-side limiters, intead of query-result limiters. In a normal scenario, I would create the NameIdentityPair object and map my result to it from the query, but using Projection, I instead specify the exact filtering I demand right in the query, and that is all the database is aware of?Dougald
Many applications read more often than they write, so a common pattern is to use projections when reading from the database, and to use fully hydrated domain objects for saving to the database. This way, reading from the database is tuned for performance, and writing to the database is tuned to taking advantage of business logic (written in your domain classes) and the tool that you're using (NHibernate saving you from most of the CRUD code). The "projection" is kind of like plucking out what data you will need so that NHibernate only asks the database for just that data when it makes the SQL.Keelin
Thank you, I think this is much clearer than what I have found so far.Dougald
B
2

If you're familiar with SQL, a projection is the SELECT clause of a query, used to select which fields from the available results to return.

For example, assume you have a Person with FirstName, LastName, Address, and Phone fields. If you want a query to return everything, you can leave off the projection, which is like SELECT * FROM Person in SQL. If you just want the first and last names, you would create a projection with FirstName and LastName -- which would be SELECT FirstName, LastName FROM Person in SQL terms.

Burson answered 26/5, 2011 at 15:8 Comment(0)
A
1

You can use projections to call sql functions like SUM, COUNT... or select single fields without return an entity.

"...Retrieving only properties of an entity or entities, without the overhead of loading the entity itself in a transactional scope. This is sometimes called a report query; it’s more correctly called projection." [NHibernate in Action]

Absent answered 26/5, 2011 at 14:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.