NHibernate Criteria API - order by max of two properties - nhibernate

I have a PrivateMessage class and I want to get list of PMs for user sorted chronologically either by CreationDate or LastAnswerDate (depending on which is more recent) using Criteria API.
How to sort by max of these two properies in Criteria API? My code looks similar to following:
var dc = DetachedCriteria.For<PrivateMessage>();
...
dc.AddOrder(new Order("???");
return (IList<PrivateMessage>)FindAll(typeof(PrivateMessage), dc);
CreationDate is DateTime and LastAnswerDate is DateTime?.
Thanks!

Order.Desc(
Projections.Conditional(
Restrictions.GtProperty("CreationDate", "LastAnswerDate"),
Projections.Property("CreationDate"),
Projections.Property("LastAnswerDate"))))

Related

Querying NHibernate on a nullable datetime

I'm having a heck of a time returning a few rows from my in-memory sqlite db that mocks an oracle db. I'm writing an NHibernate query to pull up rows by a nullable DateTime. I think I have it mapped correctly. Have a look:
The data object property:
public virtual System.Nullable<System.DateTime> RequiredInstallDt { get; set; }
The mapping:
Map(x => x.RequiredInstallDt).Column("REQUIRED_INSTALL_DT").Nullable();
There's two rows in the db. One that should be pulled up and one that shouldn't. The date I'm asking for is 2012-8-1. There's no time value and there isn't one in the db, which I've been able to verify. One row has Aug 1 and the other doesn't. I'm expecting one record returned.
If I say:
IList<Request> ra = new RequestDAO().ListAll();
which is a known working method in the same call as my query, I get the two records as expected.
I've tried several versions of the same query, using linq, hql, and the CreateCriteria versions. The result is almost always the same. I get 0 records back (the other way is a NHibernate.Hql.Ast.ANTLR.QuerySyntaxException so that's a PEBKAC). Here's one of those query versions:
DateTime installDate = new DateTime(2012, 8, 1);
var requests = session.CreateCriteria<Request>()
.Add(Restrictions.Ge("RequiredInstallDt", installDate))
.Add(Restrictions.Lt("RequiredInstallDt", installDate.AddDays(1)))
.List<Request>();
Thanks for reading.. I appreciate any input.
Try adding a not null restriction. Your query could be
DateTime installDate = new DateTime(2012, 8, 1);
var requests = session.CreateCriteria<Request>()
.Add(Restrictions.Ge("RequiredInstallDt", installDate))
.Add(Restrictions.Lt("RequiredInstallDt", installDate.AddDays(1)))
.Add(Restriction.IsNotNull("RequiredInstallDt"))
.List<Request>();

Magento: Get Collection of Order Items for a product collection filtered by an attribute

I'm working on developing a category roll-up report for a Magento (1.6) store.
To that end, I want to get an Order Item collection for a subset of products - those product whose unique category id (that's a Magento product attribute that I created) match a particular value.
I can get the relevant result set by basing the collection on catalog/product.
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToFilter('unique_category_id', '75')
->joinTable('sales/order_item', 'product_id=entity_id', array('price'=>'price','qty_ordered' => 'qty_ordered'));
Magento doesn't like it, since there are duplicate entries for the same product id.
How do I craft the code to get this result set based on Order Items? Joining in the product collection filtered by an attribute is eluding me. This code isn't doing the trick, since it assumes that attribute is on the Order Item, and not the Product.
$collection = Mage::getModel('sales/order_item')
->getCollection()
->join('catalog/product', 'entity_id=product_id')
->addAttributeToFilter('unique_category_id', '75');
Any help is appreciated.
The only way to make cross entity selects work cleanly and efficiently is by building the SQL with the collections select object.
$attributeCode = 'unique_category_id';
$alias = $attributeCode.'_table';
$attribute = Mage::getSingleton('eav/config')
->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attributeCode);
$collection = Mage::getResourceModel('sales/order_item_collection');
$select = $collection->getSelect()->join(
array($alias => $attribute->getBackendTable()),
"main_table.product_id = $alias.entity_id AND $alias.attribute_id={$attribute->getId()}",
array($attributeCode => 'value')
)
->where("$alias.value=?", 75);
This works quite well for me. I tend to skip going the full way of joining the eav_entity_type table, then eav_attribute, then the value table etc for performance reasons. Since the attribute_id is entity specific, that is all that is needed.
Depending on the scope of your attribute you might need to add in the store id, too.

Linq to Nhibernate 3.1 Group By (Or distinct)

I need to do a simple "group by" with a nhibernate query.
My try were :
(from adn in session.Query<Table>()
orderby adn.Data
select adn.Data).Distinct().ToList<string>();
and
session.Query<Table().GroupBy(adn => adn.Data).Select(dat => dat).ToList<string>()
can someone help me to find a solution ?
My goal is to retrieve all the Distinct "Data" Column.
It can be by group by or distinct.
(the 2 solutions would be better for my progression in nhibernate)
Regards
edit
Danyolviax, I tryied your solution
return (from adn in session.Query<Table>()
group adn by adn.Data into dataGroupe
select dataGroupe).ToList<string>();
It doesn't work.
I feared that I use Nhibernate 3.1 (and not 2.1)
Any correction or alternative solution ?
edit 2
In the second solution which works (^^)
I have a list of a class with one property.
In my case, I prefer to have a list of string or int.
Otherwise I should create a specific class for this case.
Do you know a trick.
And thanks for your support.
Look here:
Linq to NHibernate and Group By
here some examples:
http://msdn.microsoft.com/en-us/vcsharp/aa336754
updated
try this with 3.1.0.4000:
var ret = (from adn in session.Query<Table>()
group adn by adn.Data into dataGroup
select new {dataGroup.Key }).ToList();
update
var ret = (from adn in session.Query<Table>()
group adn by adn.Data into dataGroup
select dataGroup.Key).ToList<string>();

NHibernate sorting (SQL as a second option)

I'm using NHibernate as my ORM and I'm trying to sort some data. The data needs to be retrieved paged.
Two of the columns in my Request table are UrgencyID and CreateDate. UrgencyID is a FK to the Urgency table with static data:
1 = Low, 2 = Normal, 3 = High, 4 = Critical.
I need to order my Requests in the following manner.
Critical Requests by CreateDate descending
All other requests by CreateDate descending
So my list of Requests should always have Critical by CreateDate desc at the top and then all other Requests (disregarding UrgencyID) by CreateDate desc
Is it possible to perform this sort order in NHibernate (using the Criteria API)?
If not, how would I do this in SQL? In a stored procedure?
EDIT: Solution thanks to both #DanP and #Michael Pakhantsov
Using the this_ prefix in the sql string as this is the default NHibernate prefix for the primary table selection.
public class OperatorJobQueueOrder : Order
{
public OperatorJobQueueOrder() : base("", true) { }
public override NHibernate.SqlCommand.SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return new NHibernate.SqlCommand.SqlString("case this_.JobRequestUrgencyID when 4 then 4 else 0 end desc, this_.CreatedDate");
}
}
You may be able to create a custom sort order to handle this through the critiera api; see this question for an example implementation.
IN SQL ORDER BY will be
ORDER by case UrgencyId when 4 then 4 else 0 end, CreateDate desc

Only get latest results using nHibernate

I have a nHibernate query like this
ICriteria query = session.CreateCriteria(typeof(MyResult))
.Add(Expression.Eq("ResultTypeId", myResult.ResultTypeId))
Problem is that users add results all the time and I want to show a table of all the latest results for all the diferent ResultTypes I have.
The MyResult class has a property ResultDate. My question is, what do I add to the query to get it to only return the latest result for the given result type. There is nothing to say that the results will be in date order in the database.
Thanks,
Mark
You can order the result by ResultDate using the AddOrder method, as below:
ICriteria query = session.CreateCriteria(typeof(MyResult))
.Add(Expression.Eq("ResultTypeId", myResult.ResultTypeId))
.AddOrder(Order.Desc("ResultDate"))
.List<MyResult>();
If you want to limit the number of MyResult instances you get back, you can use the SetMaxResults method, like so:
ICriteria query = session.CreateCriteria(typeof(MyResult))
.Add(Expression.Eq("ResultTypeId", myResult.ResultTypeId))
.AddOrder(Order.Desc("ResultDate"))
.SetMaxResults(20)
.List<MyResult>();
If I understand the question well, Mark wants to see an overview of all the last results for each type.
Which means that, for every result type, he only wants to see only one row, and that is the Result which has last been added for that type.
I think that, the easiest way to achieve this, would be to create an additional class, which we can call 'MyResultOverview' for instance:
public class MyResultOverview
{
public int ResultId {get; set;}
public int ResultTypeId {get; set;}
public DateTime ResultDate {get; set;}
}
This class should not be mapped, but NHibernate should be aware that this class exists. Therefore, we'll have to import it:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" >
<import class="MyResultOverview" />
</hibernate-mapping>
Then, we can create an ICriteria which will populate instances of MyResultOverview (and which will also generate the most efficient SQL Query in order to get this overview).
It should look something like this:
ICriteria criteria = session.CreateCritera (typeof(MyResult));
criteria.SetProjection (Projections.ProjectionList ()
.Add (Projections.Property("Id"), "ResultId")
.Add (Projections.Property("ResultType"), "ResultType")
.Add (Projections.Max("ResultDate"), "ResultDate"));
criteria.SetResultTransformer (Transformers.AliasToBean (typeof(MyResultOverview)));
IList<MyResultOverview> results = criteria.List<MyResultOverview>();
This should give you a list of MyResultOverview instances which represent the MyResults that you're looking for.
Then, in order to retrieve the MyResult itself, you can simply do this by retrieving the MyResult instance for that particalur ResultId that you've retrieved as well.
I haven't tested this, nor did i compile it, but this is the path that I would follow to achieve this.
Order by ResultDate (descending) and select top whatever you feel appropriate.
In HQLthis might work:
select item, tag
from MyItem item
join item.Tags tag
where tag.Id = (
select max(tag2.Id)
from MyItem item2
join item2.Tags tag2
where item2.Id = item.Id
group by item2.Id
)