I am trying to create query which orders by child collection's property. It is quite easy in SQL:
Select Table1.*
From Table1
Inner join Table2 on Table1.Id = Table2.Table1Id
OrderBy Table1.Column1, Table2.Column1
Here is how I did it in NHibernate 2 and it worked fine:
var result = Session.Linq<Table1>()
.OrderBy(x => x.Column1)
.ThenBy(x => x.Table2.FirstOrDefault().Column1);
After migrating to NHibernate 3 this doesn't work anymore. It throws NHibernate.Hql.Ast.ANTLR.QuerySyntaxException: Antlr.Runtime.NoViableAltException.
I am using NHibernate 3.1. Are there other solutions for such query?
The two queries aren't the same. The LINQ version (roughly) equates to:
SELECT Table1.*
FROM Table1
INNER JOIN (SELECT TOP 1 * FROM Table2 WHERE Table2.Table1ID = Table1.Id) AS FirstTable2
ORDER BY Table1.Colum1, FirstTable2.Table2
EDIT
If you want to replicate the original sql you might want something like:
Session.Linq<Table1>()
.SelectMany(t1 => t1.Table2, (t1,t2) => new { t1, t2 })
.OrderBy(t1t2 => t1t2.t1.Column1)
.ThenBy(t1t2 => t1t2.t2.Column2)
.Select(t1t2 => t1)
Related
In EF7 there is a new ExecuteUpdate function to do updates on a table without retrieving the data from the server first.
Is it possible to do an update from select with this method in any way where it is using data from another table?
To be more concrete can i express this SQL in EF:
UPDATE
Table_A
SET
Table_A.col1 = Table_B.col1,
Table_A.col2 = Table_B.col2
FROM
Some_Table AS Table_A
INNER JOIN Other_Table AS Table_B
ON Table_A.id = Table_B.id
WHERE
Table_A.col3 = 'cool'
The following query updates table with values from joined table.
var query =
from a in context.TableA
join b in context.TableB on a.id equals b.id
where a.col3 == "cool"
select new { a, b };
query.ExecuteUpdate(s =>
s.SetProperty(x => x.a.col1, x => x.b.col1)
.SetProperty(x => x.a.col2, x => x.b.col2)
);
I want to change sql query to linq using join statement. The query should retrieve columns (days and startdate) while matching records of table 1 to table. In short converting sql query to linq using join statement.
Below is what i've tried.
SQL Query (Working)
SELECT *
FROM dbo."Batches"
INNER JOIN dbo.StudentBatchRelation
on dbo.Batches.Id = dbo.StudentBatchRelation.BatchId
WHERE
dbo.StudentBatchRelation.StudentId = '3d980306-e36e-4581-8c98-219717cb1668'
LINQ (not fetching result)
var result = (from t1 in contBatch.GetallBatchList()
join t2 in contStudent.getAllStudentBatchList()
on t1.Id equals t2.batchId where t2.studentId == studentid
select new { t1.Days, t1.BatchDate }).ToList();
If your EF entities are well defined, you could simplify your query with :
var result = Db.Batches
.Include(p => p.StudentBatchRelation)
.Where(p => p.StudentBatchRelation.StudentId = "3d980306-e36e-4581-8c98-219717cb1668")
.ToList();
Otherwise, if you have to use your Getallxxxx functions, you could do :
var result = (from t1 in contBatch.GetallBatchList()
join t2 in contStudent.getAllStudentBatchList()
on t1.Id equals t2.batchId
where t2.studentId == "3d980306-e36e-4581-8c98-219717cb1668"
select t1)
.ToList();
I have a navigation property, say Items, of an object, say Order. If I want to get a list of Orders, including the Items, I can do something like:
var orders = dbContext.Order.Include(o => i.Items);
This works great, but now I'd like to get only 3 items for each order and I am wondering the best way to accomplish this.
One way is to perform the following:
var orders =
(from o in dbContext.Order
join i in dbContext.Items on o.Id equals i.OrderId
select new { o.Id, i })
.GroupBy(o => o.Id)
.SelectMany(i => i.Take(3))
This works well, although the generated SQL is is bit complex, but I am wondering if there is a more direct (or performant) way.
Thanks,
Eric
var orders = dbContext.Order
.Select(o => new
{
Order = o,
Items = o.Items.Take(3)
})
.AsEnumerable()
.Select(a => a.Order)
.ToList();
This will fill the Order.Items collection with the top 3 items automatically if
you don't disable change tracking (not the case in the query above)
the relationship between Order and Item is not many-to-many (probably not the case because orders and items usually have a one-to-many relationship)
Edit
The generated SQL query is:
SELECT
[Project2].[Id] AS [Id],
[Project2].[C1] AS [C1],
[Project2].[Id1] AS [Id1],
[Project2].[OrderId] AS [OrderId],
FROM (SELECT
[Extent1].[Id] AS [Id],
[Limit1].[Id] AS [Id1],
[Limit1].[OrderId] AS [OrderId],
CASE WHEN ([Limit1].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM [dbo].[Orders] AS [Extent1]
OUTER APPLY (SELECT TOP (3)
[Extent2].[Id] AS [Id],
[Extent2].[OrderId] AS [OrderId],
FROM [dbo].[Items] AS [Extent2]
WHERE [Extent1].[Id] = [Extent2].[OrderId] ) AS [Limit1]
) AS [Project2]
ORDER BY [Project2].[Id] ASC, [Project2].[C1] ASC
How bad is the performance? If it's tolerable then I'd leave it alone. There's not a straight-forward way to do this in SQL either. Usually you end up with a sub-query that computes the ROW_NUMBER partitioned by your grouping, then returning rows where the row number is less than n.
Since there's not a direct translation of that mechanism to Linq, I'd keep the Linq understandable and not worry about the complexity of the generated SQL unless it's a SIGNIFICANT performance problem.
You could also compare it to the performance of returning ALL items then filtering using Linq-to-Objects.
Another option would be to code this as a stored procedure instead of trying to do it in Linq.
This should generate simple SQL in the form of an OUTER APPLY with top 3 statement to Items. We then have to do some grouping using linq-to-objects, but only the data we need have been brought from the server.
var orders =
(from o in dbContext.Order
from i in (from x in dbContext.Items
where o.Id == x.OrderId
select x).Take(3).DefaultIfEmpty()
select new
{
Order = o,
Item = i
}).AsEnumerable()
.GroupBy(x => x.Order)
.Select(x => new { Order = x.Key, Items = x.Select (y => y.Item ) });
And if you only want the top 3 items per order without the order entity. Will generate CROSS APPLY with top statement in SQL to items.
var items =
from o in dbContext.Order
from i in (from x in dbContext.Items
where o.Id == x.OrderId
select x).Take(3)
select i;
I am trying to convert a ASP.NET project to Entity framework. How to re-write the following query to its LINQ equivalent?
SELECT {Table1 objects}
FROM [Table1] tb1
INNER JOIN [Table2] tb2
ON tb1.Table1ID = tb2.fk_Table1ID
WHERE tb2.fk_attrib1 = '123' AND tb2.fk_attrb2 = '345'
ORDER BY tb1.attrib1
The result is a collection of Table1 objects.
Here Table1 and Table2 correspond to object System.Data.Objects.ObjectSet of ADO.NET Entity Framework.
var results = from tb1 in Context.Table1
join tb2 in Context.Table2 on tb1.Table1ID == tb2.fk_Table1ID
where tb2.fk_attrib1 == "123" && tb2.fk_attrb2 == "345"
orderby tb1.attrib1
select tb1;
Something like this:
context.Table1
.Where( o => o.Table2s.Any( o2 =>
o2.fk_attrib1 == '123' &&
o2.fk_attrib2 == '345' ) )
.OrderBy( o => o.attrib1 )
.ToList();
BTW, LINQPad is great for trying out L2E queries.
This should help you a little bit. I suppose the main problem is with JOIN clause - in EF you can use NavigationProperties and don't need to worry about joining tables - EF will take care of that for you.
Also you are trying to filter on column from joined table. This you can do using Any method to find all Table1 elements that are connected to Table2 where those referenced elements have certain properties/columns. You should also get familiar with All method, as it might be useful to you in future.
from t1 in context.Table1
where t1.Table2s.Any(t2.fk_attrib1 == "123" && t2 => t2.fk_attrb2 == "345")
order by t1.attrib1
select t1;
Edit:
I assume that there is 1:n relationship between Table1 and Table2 which results in enumerable collection as NavigationProperty in Table1 objects.
Edit2:
Fixed error in code - didn't noticed that both attributes are from Table2 not Table1
Should be something like this:
var result = (from tb1 in Table1
from tb2 in Table2
where tb1.Key == tb2.Key &&
tb2.fk_attrib1 = '123' &&
tb2.fk_attrb2 = '345'
select ione).OrderBy(p=>p.attrib1);
Hope this helps.
var result = table1.Join(table2, o => o.ProgramID, t => t.ProgramID, (o, t) => new { o.ProgramID, t.Program })
.OrderBy(t => t.Program)
.Distinct();
the above linq statement actually returns the correct result, but he sql generated (below) is not as simple as it could be
SELECT [t2].[ProgramID], [t2].[Program]
FROM (
SELECT DISTINCT [t0].[ProgramID], [t1].[Program]
FROM [table1] AS [t0]
INNER JOIN [table2] AS [t1] ON [t0].[ProgramID] = [t1].[ProgramID]
) AS [t2]
ORDER BY [t2].[Program]
I would have thought the sql below is far cleaner but I'm not sure of the linq statement to achieve it.
select distinct
o.ProgramID,
t.Program
from
table1 0
inner join table2 t on t.ProgramID = o.ProgramID
order by t.Program
Thanks in advance
I don't know if it will help, but you can try something like this;
var result = (from o in table1
join t in table2 on o.ProgramID equals t.ProgramID
orderby t.Program
select new { o.ProgramID, t.Program }).Distinct();
I tried this and that works:
var result = (from o in table1
join t in table2 on o.ProgramID equals t.ProgramID
select new { o.ProgramID, t.Program })
.Distinct().OrderBy(t => t.Program)
.ThenBy(t => t.ProgramName)
.ThenBy(t => t.Description);
First you do Distinct and then OrderBy, then OrderBy works.
Profile the two queries, comparing stats-IO and the actual execution plan. It is entirely possible that it makes zero difference to the SQL server.
If you really want known TSQL, use ExecuteQuery-of-T and pass in the TSQL yourself. Maybe include some lock hints too (most commonly: NOLOCK)