NHibernate Linq query join subquery on two column - linq

A "case" can have many action types and each action is logged in a journal.
I want to show a list of "cases" only with the latest journal entry
This is the T-SQL sub query
SELECT SagId, max(Dato) as maxdate FROM vOpgaveliste o group by SagId
And this is the T-SQL main query
select o.* from
(
SELECT SagId, max(Dato) as maxdate
FROM vOpgaveliste o
group by SagId
)
as nyeste
join vOpgaveliste o on o.SagId = nyeste.SagId and o.Dato = nyeste.maxdate
I can create the subquery in linq
var queryInner = from o in query
where o.SagsbehandlerInit == "chr"
where o.Dato >= DateTime.Today && o.Dato <= DateTime.Today.AddDays(-7)
group o by o.SagId
into g
select new { SagId = g.Key, MaxDate = g.Max(d => d.Dato) };
I then created this query
var outer = from o in query
from s in queryInner
where s.SagId == o.SagId && s.MaxDate == o.Dato
select o;
But NHibernate throws a System.NotSupportedException was unhandled by user code exception
I also tried this syntax https://stackoverflow.com/a/16918106/1147577 but get an syntax error on the join statement
Thanks

NHibernate simply does not support sub queries within from statement block. It only supports it in the Select and Where block.
I guess you have to figure out another way to get your result.
Of course the linq to object or many other linq providers support all kind of crazy query constructs, the linq to Nhibernate implementation simply has tons of limitations.

Related

How to get TOP 1 result from a LINQ left join without APPLY

I have a master table and I intend to use a left join with LINQ.
Unfortunately the left join multiplies the result (I need only a top 1 result from that).
Here comes the problem: my query should have SQL 8 conformance.
So when I use the following query:
var query = from user in context.User
join group in context.Groups on user.ID equals group.GroupID into groupJoin
from subGroup in groupJoin.Take(1).DefaultIfEmpty()
select new
{
Name = user.Name,
GroupName = subGroup!=null ? subGroup.Name : null
};
I get this exception:
The execution of this query requires the APPLY operator, which is not
supported in versions of SQL Server earlier than SQL Server 2005.
How could I replace my query to have SQL8 conformance?
Unfortunately I have no EF4 to test (it does the trick in the latest EF6), but you can try to force usage of a SQL subquery expression(s) like this:
var query = from user in context.User
select new
{
Name = user.Name,
GroupName = (from g in context.Groups where g.GroupId == user.Id select g.Name).FirstOrDefault()
};
Used your linq-query without take(1) and after that use next code:
query = query.Take(1);

LINQ query (or lambda expression) to return records that match a list

I have a list of strings (converted from Guid) that contains the ID's of items I want to pull from my table.
Then, in my LINQ query, I am trying to figure out how to do an in clause to pull records that are in that list.
Here is the LINQ
var RegionRequests = (from r in db.course_requests
where PendingIdList.Contains(r.request_state.ToString())
select r).ToList();
It builds, but I get a run error: "System.NotSupportedException: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression".
I would prefer to compare guid to guid, but that gets me nowhere.
Can this be converted to a lambda expression? If that is best, how?
LINQ to Entites tries to convert your expression to an SQL Statement. Your server didn't know the stored procedure ToString().
Fix:
var regionRequests =
from r in db.course_requests.ToList()
where PendingIdList.Contains(r.request_state.ToString())
select r;
With db.course_requests.ToList() you force LINQ to materialize your database data (if big table, you gonna have a bad time) and the ToString() is executed in the object context.
You stated: I have a list of strings (converted from Guid) ...
Can you NOT convert them into strings and keep it as a List< System.Guid>?? Then you can do this (assuming PendingIdGuidList is List< System.Guid>:
var regionRequets = (from r in db.course_requests
join p in PendingIdGuidList on u.request_state equals p
select r).ToList();
Edited to add:
I ran a test on this using the following code:
var db = new EntityModels.MapleCreekEntities();
List<System.Guid> PendingIdGuidList =
new List<System.Guid>() {
System.Guid.Parse("77dfd79e-2d61-40b9-ac23-36eb53dc55bc"),
System.Guid.Parse("cd409b96-de92-4fd7-8870-aa42eb5b8751")
};
var regionRequets = (from r in db.Users
join p in PendingIdGuidList on r.Test equals p
select r).ToList();
Users is a table in my database. I added a column called Test as a Uniqueidentifier data type, then modified 2 records with the following Guids.
I know it's not exactly a 1:1 of what the OP is doing, but pretty close. Here is the profiled SQL statement:
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[UserLogin] AS [UserLogin],
[Extent1].[Password] AS [Password],
[Extent1].[Test] AS [Test]
FROM [dbo].[Users] AS [Extent1]
INNER JOIN (SELECT
cast('77dfd79e-2d61-40b9-ac23-36eb53dc55bc' as uniqueidentifier) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
cast('cd409b96-de92-4fd7-8870-aa42eb5b8751' as uniqueidentifier) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1] ON [Extent1].[Test] = [UnionAll1].[C1]

Linq: Orderby when including multiple tables

Currently learning Linq to Entity. I been successful, but came stumped with the orderby clause and its use with multiple tables.
var query = from k in contxt.pages.Include("keywords")
where k.ID == vals.pageId select k;
My understanding with the code above is it creates an inner join where ID is equal to pageId.
So what I am having a difficult time visualizing is how I would perform an orderby on both tables?
I would like to sort on both tables.
I have tried:
var query = from k in contxt.pages.Include("keywords") where k.ID == vals.pageId orderby k.keywords.**?** select k;
The question mark is not supposed to be there. I am showing that the column that I would like to sort by isn't there. Trying this k.Kegwords. doesn't show the column.
I would write a SQL query as follows:
string query = "SELECT pages.page, pages.title, pages.descp, keywords.keyword
FROM pages INNER JOIN keywords ON pages.ID = keywords.pageID
ORDER BY keywords.sort, pages.page";
pages and keywords have a 1 to many relationship, which FK keywords.
Thank you,
deDogs
Here you go.
var result = (from x in pages
join y in keywords on x.ID equals y.pageID
orderby y.sort, x.page
select new
{
x.Page,
x.title,
x.descp,
y.keyword
});

Linq to entities Left Join

I want to achieve the following in Linq to Entities:
Get all Enquires that have no Application or the Application has a status != 4 (Completed)
select e.*
from Enquiry enq
left outer join Application app
on enq.enquiryid = app.enquiryid
where app.Status <> 4 or app.enquiryid is null
Has anyone done this before without using DefaultIfEmpty(), which is not supported by Linq to Entities?
I'm trying to add a filter to an IQueryable query like this:
IQueryable<Enquiry> query = Context.EnquirySet;
query = (from e in query
where e.Applications.DefaultIfEmpty()
.Where(app=>app.Status != 4).Count() >= 1
select e);
Thanks
Mark
In EF 4.0+, LEFT JOIN syntax is a little different and presents a crazy quirk:
var query = from c1 in db.Category
join c2 in db.Category on c1.CategoryID equals c2.ParentCategoryID
into ChildCategory
from cc in ChildCategory.DefaultIfEmpty()
select new CategoryObject
{
CategoryID = c1.CategoryID,
ChildName = cc.CategoryName
}
If you capture the execution of this query in SQL Server Profiler, you will see that it does indeed perform a LEFT OUTER JOIN. HOWEVER, if you have multiple LEFT JOIN ("Group Join") clauses in your Linq-to-Entity query, I have found that the self-join clause MAY actually execute as in INNER JOIN - EVEN IF THE ABOVE SYNTAX IS USED!
The resolution to that? As crazy and, according to MS, wrong as it sounds, I resolved this by changing the order of the join clauses. If the self-referencing LEFT JOIN clause was the 1st Linq Group Join, SQL Profiler reported an INNER JOIN. If the self-referencing LEFT JOIN clause was the LAST Linq Group Join, SQL Profiler reported an LEFT JOIN.
Do this:
IQueryable<Enquiry> query = Context.EnquirySet;
query = (from e in query
where (!e.Applications.Any())
|| e.Applications.Any(app => app.Status != 4)
select e);
I don't find LINQ's handling of the problem of what would be an "outer join" in SQL "goofy" at all. The key to understanding it is to think in terms of an object graph with nullable properties rather than a tabular result set.
Any() maps to EXISTS in SQL, so it's far more efficient than Count() in some cases.
Thanks guys for your help. I went for this option in the end but your solutions have helped broaden my knowledge.
IQueryable<Enquiry> query = Context.EnquirySet;
query = query.Except(from e in query
from a in e.Applications
where a.Status == 4
select e);
Because of Linq's goofy (read non-standard) way of handling outers, you have to use DefaultIfEmpty().
What you'll do is run your Linq-To-Entities query into two IEnumerables, then LEFT Join them using DefaultIfEmpty(). It may look something like:
IQueryable enq = Enquiry.Select();
IQueryable app = Application.Select();
var x = from e in enq
join a in app on e.enquiryid equals a.enquiryid
into ae
where e.Status != 4
from appEnq in ae.DefaultIfEmpty()
select e.*;
Just because you can't do it with Linq-To-Entities doesn't mean you can't do it with raw Linq.
(Note: before anyone downvotes me ... yes, I know there are more elegant ways to do this. I'm just trying to make it understandable. It's the concept that's important, right?)
Another thing to consider, if you directly reference any properties in your where clause from a left-joined group (using the into syntax) without checking for null, Entity Framework will still convert your LEFT JOIN into an INNER JOIN.
To avoid this, filter on the "from x in leftJoinedExtent" part of your query like so:
var y = from parent in thing
join child in subthing on parent.ID equals child.ParentID into childTemp
from childLJ in childTemp.Where(c => c.Visible == true).DefaultIfEmpty()
where parent.ID == 123
select new {
ParentID = parent.ID,
ChildID = childLJ.ID
};
ChildID in the anonymous type will be a nullable type and the query this generates will be a LEFT JOIN.

Join in linq: "The specified LINQ expression contains references to queries that are associated with different contexts."

Is it possible to make a join in linq and only return data from one dataset where the other key was present, a little like:
var q = from c in customers
join o in orders on c.Key equals o.Key
select new {c.Name, o.OrderNumber};
and then instead of returning just the two records then returning customers like:
var q = from c in customers
join o in orders on c.Key equals o.Key
select c;
When I try to do (something similar) I get this error:
The specified LINQ expression contains references to queries that are associated with different contexts.
I going to assume that you've skipped a Where clause which involved the orders table (or otherwise the join would be pointless)
In which case, you can just have Linq infer the join.
var q = from c in customers
where c.Orders.Any(o=> o.ProductCode == productCode)
select c;
Linq2Sql will automatically create the Orders property if you have a foreign key defined; I believe with the Entity Framework, you have to manually specify it.
The error indicates an other problem:
You have to use the same DataContext on every object in the query if you're using Linq to SQL.
Your code should look somehow like that:
using (MyDataContext dc = new MyDataContext())
{
var q = from c in dc.customers
join o in dc.orders on c.Key equals o.Key
select c;
// process q within the DataContext
// the easies would be to call q.ToList()
}
Will it be in EF 4.0 to create join from multiple context?
For example:
TestModelEntities e1 = new TestModelEntities();
TestModelEntities e2 = new TestModelEntities();
var d = from firme1 in e1.firme
join g in e2.grad on firme1.grad.grad_id equals g.grad_id
select firme1;

Resources