NHibernate entity mapping: Customer with latest order - nhibernate

I am developing a MVC3 application in c# and I am using NHibernate for the ORM part. I need to generate a list of all registered customers and their latest order. On the application side, this would require to go through all customers and retrieve all their orders to extract the latest one.
Unneeded overhead, isn't it?
On the database, I could create a view and model the entity accordingly, but then I cannot create new customers due to the fact that populating a view is not possible. So, any ideas or best practices how you solved such issues? Here's a sql query that would serve the needed information:
SELECT c.id, c.name, c.description, m.ordernumber AS latest_order, m.unixtime, m.id AS latest_order_id
FROM dbo.customer c
LEFT JOIN dbo.mailorder m ON c.id = m.customer_id
WHERE m.unixtime = (SELECT MAX(unixtime) FROM dbo.mailorder)
Any help is very much appreciated!
Best regards,
Martin

You can use formula to get last order for customer, something like this:
<property name="LatestOrder" formula="(SELECT MAX(dbo.mailorder.unixtime) FROM dbo.mailorder where dbo.mailorder.customer_id = ID)" />

Related

Querying many to many relationship

Every article I need to solve my problem seems to be in C# and I need a solution in VB.NET.
I'm using EF 6.0 with Database First model. Let me use the classic Customer product scenario to demonstrate my situation. In my database I have three tables Customer, Product and CustomerProduct. See this example in this link as mine is exactly the same.
After I generate my model from the database, my entity model diagram shows that the CustomerProduct has disappeared as expected and the the model shows a many to many relationship between Customer and Product also as expected with navigational properties of Products in Customer and Customers in Product.
All I want to do is find the product related to a customer pull out some data from both tables namely CustName and ProductName.
The SQL I would use is:
SELECT c.CustName, p.ProductName FROM Customer c
INNER JOIN CustomerProduct cp on c.CustomerId = cp.CustomerId
INNER JOIN Product p on cp.ProductId = p.ProductId
WHERE c.CustomerId=101
I don't know how to use the Addresses navigational property to access the Address data in one query.
You include them and then access them via the property in the Entity class.
Dim query = model.User.Include("Address").Include("UserAddressLink").Where(Function(o) o.UserId = 101).FirstOrDefault
If Not query Is Nothing Then
Dim houseNumber = query.Address.HouseNo 'uses the navigation property
End If
Thanks to InteXX I managed to work it out. This is my whole solution
Using db as new CustProdEntities
Dim query = db.Customers.Include(Function(U) U.Products).ToList
txtCustomer.Text = query.First.CustName
txtProduct.Text query.First.Products.First.ProdName
End Using
The bit I was stuck on was having to filter twice to the Product data. I'm not sure if there's an easier way to do this but it works for now.

SQL Query Accross Three Tables Requiring Different Joins

I have 3 tables. An Applications (relevant field is AppID) table containing information about various application available to download, a Packages table (relevant field is PackageID) containg information on the various downloadable items available and an App/Packages table (relevant field is AppID and PackageID) which shows which packages should be downloaded for each application. I need a query to find out which packages are not related to a specific application.
My idea was to INNER JOIN Applications to AppPackages to get a list of all the packages that are related to an Application and then OUTER JOIN this resultant set to Packages and find all the null results to show which packages were not related.
The problem is I can't seem to work out how to chain these queries. Subqueries don't seem to work, and EXIST/NOT EXIST requires information from the outer query which I just can't make work. I'm assuming there's something simple I'm mising, but all the literature I read is for two tables, never more than two.
This is my best attempt, but the EXISTS part doesn't work for the reason mentioned above.
SELECT Packages.PackageID FROM Packages WHERE NOT EXISTS
(Select AppPackages.PackageID, AppPackages.AppID FROM AppPackages WHERE AppPackages.AppID = #AppID)
Thanks in advance for any help :)
Cheers,
Matt :)
I need a query to find out which packages are not related to a specific application.
SELECT
*
FROM
Packages p
WHERE
NOT EXISTS (
SELECT 1
FROM Applications a
INNER JOIN AppPackages ap ON ap.PackageId = p.PackageId
WHERE ap.AppId = <Your App ID>
)
I would try sth like this:
SELECT Packages.PackageID FROM Packages WHERE Packages.PackageID NOT IN
(Select AppPackages.PackageID FROM AppPackages WHERE AppPackages.AppID = #AppID)

NHibernate Using SetProjection To Retrieve Individual Collection Items

I am trying to use Projections to Create a DTO from a Lead class. My DTO has, for example, a Home phone number, a mobile number and an email address, but the Lead Class has a collection of contact details. So I'm trying to find a way to retrieve each contact detail so that I can set the properties on the dto. I have tried using sub queries and projections but to no avail.
The SQL I'm trying to generate is something like this:
SELECT
A.LeadId,
B.ContactId,
B.Value,
C.ContactId,
C.Value,
D.ContactId
FROM Lead A
LEFT JOIN ContactDetail B ON A.LeadId=B.LeadId AND B.ContactType='Home Number'
LEFT JOIN ContactDetail C ON A.LeadId=C.LeadId AND C.ContactType='Mobile Number'
LEFT JOIN ContactDetail D ON A.LeadId=D.LeadId AND D.ContactType='Email Address'
So in short I'm trying to join to the same table 3 times based on different criteria, and I know that in NHibernate I can't use CreateAlias to join to the same table more than once and I'm anxious to know if this is possible using either the Criteria API or NHIbernate Linq. Thanks in advance for any help.
I would load the "regular" lead instance from nHibernate with its contact detail collection. Then I would use AutoMapper, to map it to the DTO class.
In my opinion, this is a much cleaner approach since you do not create special data access methods just for "simple" DTO mappings. And it's easier for refactoring since everything is expressed via "c sharp code".
Link to AutoMapper

using lazy loading on property in nhibernate

In my product entity i have the following property. It works correctly and returns back the number of stock available. Looking at my profiler i can see that this statement is called everytime i call the product entity which is causing performance issues. Is there a way i can only call this property when needed. I've added 'lazy=true' but it is still called everytime. I'm using nhibernate 2. I'd prefer not to upgrade if poss.
<property name="StockAvailable" lazy="true" type="Int32" formula="(SELECT Stock - isnull((select Sum(oi.Quantity) from OrderItems oi inner join Orders o on oi.OrderId = o.Id where (oi.OrderItemStatusId = 0 or oi.OrderItemStatusId = 1) and o.OrderStatus = 3 and oi.ProductId = Id), 0))"/>
Lazy properties are only supported from NHibernate 3 and up, so you need to upgrade if you want that property to be on your entity.
Another possiblity is to create an entity which is lazy-loaded and has just this single property on it (you could even map it to the same table).
I don't know if this is an issue to you, but you should also consider creating a view for that calculation which uses group by. This is important if you want to load not a single but many entities at the same time as group by usually performs mich better than a subselect.
http://ayende.com/Blog/archive/2010/01/27/nhibernate-new-feature-lazy-properties.aspx
Looking at the date I don't think that made it into 2.1.2, since that was released in nov 2009.

Nhibernate: left outer join on subquery

Update take 2
here is the two queries i'm working with (paging is omitted in both queries)
i'd like to get the following query
SELECT *
FROM product
LEFT OUTER JOIN
(
SELECT *
FROM Cart
LEFT OUTER JOIN
cartproducts
ON Cart.Id = cartproducts.Cart_id
WHERE Cart.username = 'user'
)
AS CartFiltered
ON product.Id = CartFiltered.product_id
but i always seem to get
SELECT *
FROM product
LEFT OUTER JOIN
cartproducts
ON product.Id = cartproducts.Product_id
LEFT OUTER JOIN
Cart
ON
cartproducts.cart_id = cart.id
WHERE Cart.username = 'user'
How can i manage to create the first type of query?
I hope my question is clearer :) lack of clarity is sometimes a great enemy of mine :p
Update:
FWIW, i still haven't found the answer, and am currently loading the paged product data and the whole cart to display the correct object.
Crude solution but it works and it beats the combinatorials i've been through trying to make the Criteria API recognize me as its master. I would be very interested if somebody could happen to point me in the right direction though ;)
Hello,
i'm having a hard time writing the following query in the Criteria API, and i don't really see how to do it: i hope some people can help.
On the database, i have products. Theses products can be in many carts (one cart per user), and each cart can contain many products, so we have a manytomany relationship.
I would like to display a list of every product, along with a small icon next to it to inform the user that this particular product is already in the cart. What i did is i asked NHibernate for my products, and to do a left outer join on carts filtered by the cart's owner.
Dim critPage As ICriteria = Session.CreateCriteria(GetType(Product)) _
.SetFirstResult(pageNumber * itemsPerPage).SetMaxResults(itemsPerPage) _
.CreateCriteria("Carts", "c", SqlCommand.JoinType.LeftOuterJoin) _
.SetProjection(plist) _
.SetResultTransformer(New TypedResultTransformer(Of ProductWithCartInfo)) _
.Add(Expression.Eq("c.User", username))
the projection list is here to reduce the number of columns to what's interesting for the ProductWithCartInfo class. It contains only property projections.
The problem is that with this query, the cart filtering is applied to the whole result set and i don't see every product with its presence in the user's cart, but rather every product in the user's cart.
Is it possible to do a left outer join on a subquery with the Criteria API in Nhibernate? For information, i would like to keep it in the Criteria API if possible.
Thanks
I'm not sure I entirly follow your issue but it sounds very similar to an issue I had. I seems that when you have the nested (sub) criteira with NHibernate you loose some of the control. I was able to get around my issue but aliasing my tables instead of using the nested criteira.
Possibly try...
criteria.CreateAlias("Cart", "Cart", JoinType.LeftOuterJoin);
and then your filter on the cart will have to be an OR condition
ICriterion cartCriterion = Restrictions.Eq("Cart.User", username);
customerCriterion = Restrictions.Or(customerCriterion, Restrictions.IsNull("Cart.User"));
criteria.Add(customerCriterion);
Let me know if that helps you out... if not... maybe post the SQL that your criteria above is generating and where it needs to change.
Good Luck