Is it possible to do eager loading with HQL without touching mappings? The "left join fetch" expression is completely ignored by nHibernate.
var query = Session.CreateQuery("from o in Member left join fetch o.Photos");
query.List<Member>();
The generated SQL is
SELECT this_.Id as Id7_1_, this_.Name as Name7_1_, this_.AltNames as AltNames7_1_,
this_.Tags as Tags7_1_, this_.Loved as Loved7_1_, profile2_.id as id6_0_,
profile2_.Website as Website6_0_, profile2_.Email as Email6_0_,
profile2_.Shop as Shop6_0_
FROM Member this_
left outer join member_profile profile2_ on this_.Id=profile2_.id
limit 10;
And then 10 statements grabbing the photos. MemberProfile is mapped as OneToOne.
You could use the fetch keyword:
from Cat as cat inner join fetch cat.Mate
This will eagerly load the Mate association.
Related
Hello I have the a linq query that I have created for a left outer join. I am wondering why linq creates the Sql it does, and how to make it a better query.
here's the c# query:
var query=
(
from subject in subjects
join statement in statements.DefaultIfEmpty() on subject.Id equals statement.SubjectId
select subject
);
query.Take(100).Dump();
and the Sql that it sends:
SELECT TOP (100)
--some fields here
FROM [Subject] AS [t0]
INNER JOIN ((
SELECT NULL AS [EMPTY]
) AS [t1]
LEFT OUTER JOIN [SubjectStatement] AS [t2] ON 1=1 ) ON [t0].[id] = [t2].[SubjectId]
What I would like to see sent is
SELECT TOP(100)
--some fields here
FROM Subject
LEFT OUTER JOIN SubjectStatemnt ON Subject.Id = SubjectStatement.Id
Is there a way to control the Sql that is being passed to Sql Server?
You are using the syntax of an inner join and while that might work out some times, you would normally create a left join using the following syntax:
var query =
(
from subject in subjects
join statement in statements on subject.Id equals statement.SubjectId into ljStatement
from statement in ljStatement.DefaultIfEmpty()
select subject
);
query.Take(100).Dump();
This would result in:
SELECT TOP (100) [t0].[Id]
FROM [Subject] AS [t0]
LEFT OUTER JOIN [SubjectStatement] AS [t1] ON [t0].[Id] = [t1].[SubjectId]
into (C# Reference)
The into contextual keyword can be used to create a temporary
identifier to store the results of a group, join or select clause into
a new identifier.
join clause (C# Reference)
A join clause with an into expression is called a group join.
...
A group join produces a hierarchical result sequence, which associates elements in the left source sequence with one or more matching elements in the right side source sequence. A group join has no equivalent in relational terms; it is essentially a sequence of object arrays.
If no elements from the right source sequence are found to match an element in the left source, the join clause will produce an empty array for that item. Therefore, the group join is still basically an inner-equijoin except that the result sequence is organized into groups.
I want to know which one is better for performance:
//Logical
var query = from i in db.Item
from c in db.Category
where i.FK_IdCategory == c.IdCategory
Select new{i.name, c.name};
or
//Join
var query2 = from i in db.Item
join c in db.Category
on c.ID equals i.FK_IdCategory
Select new{i.name, c.name};
Performance of the two queries really depends on which LINQ provider and which RDBMS you're using. Assuming SQL Server, the first would generate the following query:
select i.name, c.name
from Item i, Category c
where i.FK_idCategory = c.IdCategory
Whereas the second would generate:
select i.name, c.name
from Item i
inner join Category c
on i.FK_idCategory = c.IdCategory
Which operate exactly the same in SQL Server as is explained in: Explicit vs implicit SQL joins
This depends on the ORM you're using and how intelligent it is at optimizing your queries for your backend.
Entity Framework can generate some pretty awful SQL if you don't do your linq perfectly, so I'd assume query2 is better.
The only way for you to know for sure would be to inspect the SQL being generated by the two queries.
Eyeballing it, it looks like query1 would result in both tables being pulled in their entirety and then being filtered against each other in your application, while query2 will for sure generate an INNER JOIN in the query, which will let SQL Server do what it does best - set logic.
Is that FK_IdCategory field a member of an actual foreign key index on that table? If not, make it so (and include the name column as an included column in the index) and your query will be very highly performant.
With linq2Sql or EntityFramework, you would probably do something like this:
var query = from i in db.Item
select new {i.name, i.Category.Name}
This will generate a proper SQL inner join.
I do assume that there is a foreign key relation between Item and Category defined.
I've a question about a SQL query.. I'm building a prototype webshop in ASP.NET Visual Studio. Now I'm looking for a solution to view my products. I've build a database in MS Access, it consists of multiple tables.
The tables which are important for my question are:
Product
Productfoto
Foto
Below you'll see the relations between the tables
For me it is important to get three datatypes: Product title, price and image.
The product title, and the price are in the Product table. The images are in the Foto table.
Because a product can have more than one picture, there is a N - M relation between them. So I've to split it up, I did it in the Productfoto table.
So the connection between them is:
product.artikelnummer -> productfoto.artikelnummer
productfoto.foto_id -> foto.foto_id
Then I can read the filename (in the database: foto.bestandnaam)
I've created the first inner join, and tested it in Access, this works:
SELECT titel, prijs, foto_id
FROM Product
INNER JOIN Productfoto
ON product.artikelnummer = productfoto.artikelnummer
But I need another INNER JOIN, how could I create that? I guess something like this (this one will give me an error)
SELECT titel, prijs, bestandnaam
FROM Product
(( INNER JOIN Productfoto ON product.artikelnummer = productfoto.artikkelnummer )
INNER JOIN foto ON productfoto.foto_id = foto.foto_id)
Can anyone help me?
something like this should work:
SELECT Product.titel, Product.prijs, Foto.bestandnaam FROM Product INNER JOIN
(Foto INNER JOIN Productfoto ON Foto.[foto_id] = Productfoto.[foto_id]) ON
Product.[artikelnummer] = Productfoto.[artikelnummer];
One thing about the use of linking tables
The ProductFoto table allows for N-M relations between Product and Foto indeed. Is this what you really want/need? In other words, can one Foto belong to more than one Product? If not, put the Product_Id on the Foto table. If so,...
...let's discuss JOIN.
Say we have two tables, A and B. doing a
SELECT * FROM A, B
will give you all permutations of A's rows with B's rows. We could limit the resultset by adding a WHERE clause, like WHERE A.a='lekker hoor!', or a way cooler WHERE A.id=B.a_id. Which actually starts to look like a JOIN result!
Lets do a proper JOIN then:
SELECT * FROM A JOIN B ON A.id=B.a_id
JOINs actually come in LEFT OUTER, RIGHT OUTER and FULL INNER or FULL OUTER joins.
A LEFT JOIN (use of OUTER is optional) will contain all records in the left (first) table, even if there is no corresponding records(s) in the right (second) table.
A RIGHT JOIN obviously works the same way, but mirrored.
With a FULL OUTER JOIN both tables are optional (not quite the same as SELECT * FROM A, B though!).
A FULL INNER needs matching records from both tables (this is the default).
When you do want to do more than one JOIN, say
SELECT * FROM
A
JOIN B ON A.id=B.a_id
JOIN C ON B.id=C.b_id
You can think of the extra JOIN as joining on an intermediate table, formed by joining A and B, especially when mixing some LEFT/RIGHT/INNER/OUTER JOINs.
As to your question
Use something along the lines of
SELECT TOP (1) titel, prijs, bestandnaam
FROM
( -- this bracket is MS Access specific (and awkward)
Product
INNER JOIN Productfoto ON product.artikelnummer = productfoto.artikelnummer
) -- this one too
INNER JOIN foto ON productfoto.foto_id = foto.foto_id
to satisfy MS Access, use brackets around first two tables, see Ms-Access: Join 3 Tables
Normally no brackets required (you'll get to use them like this when you discover sexy sub-selects, for which the rule is: only use them if there is no alternative).
Because there are multiple matches in your ProductFoto table, there are multiple matches in your result. Use TOP 1 (or LIMIT 1, depending on your DB) to 'fix' this.
Veel success, en doe jezelf een plezier en switch to English!
1) First issue I'm having is if you do an include and then an order by the SQL generated generates an inner join and an outer join
var query = from l in Lead.Include("Contact")
orderby l.Contact.FirstName
select l;
Which generates the following inner join and outer join on the same table
INNER JOIN [dbo].[Contact] AS [Extent2]
ON [Extent1].[ContactId] = [Extent2].[ContactId]
LEFT OUTER JOIN [dbo].[Contact] AS [Extent3]
ON [Extent1].[ContactId] = [Extent3]. [ContactId]
ORDER BY [Extent2].[FirstName] ASC
Which makes for a slightly inefficient query
2) if I do multiple includes it always does the second one as an outer join so like
Lead.Include("OneToOne").Include("OtherOneToOne") <- in this scenario
OtherOneToOne is an outer
join and OneToOne is an inner
join
Lead.Include("OtherOneToOne").Include("OneToOne") <- in this scenario
OneToOne is an outer join
and OtherOneToOne is an
inner join
is that just how it works?
I found another post where someone was talking about this and they said that it was fixed in the June CTP release
http://blogs.msdn.com/b/adonet/archive/2011/06/30/announcing-the-microsoft-entity-framework-june-2011-ctp.aspx
But I installed and setup that to be used and it still doesn't work..
alright it won't let me answer my own question
so
EDIT:
Alright I setup an isolated test and found that http://blogs.msdn.com/b/adonet/archive/2011/06/30/announcing-the-microsoft-entity-framework-june-2011-ctp.aspx seems to have resolved these
But since I'm using RIA I'm out of luck since the june ctp doesn't support RIA :-/
A solution is to do the include yourself:
var query = from l in Lead
select new { l, l.Contact } into row
orderby row.Contact.FirstName
select row;
In NHibernate HQL you can select multiple entities for a given query like this example.
var query = session.CreateQuery("select c,k from Cat as c join c.Kittens as k");
Obviously the real world situation has more complexity but that is the basics. Is there a way to do this in a Criteria query?
You need to use JOIN FETCH.
HQL would be this -
FROM Cat C JOIN FETCH C.Kittens
var catsWithKittens = session.createCriteria()
.SetFetchmode("Kittens", Fetchmode.Eager)
.List();