I am new to linq so I apologize in advance if it a dumb question. I inherited the following query and it is not producing correct results in order to fix it I have to understand what it is doing.
Here is the query.
using (var dbCtx = new TLMDbContext())
{
var dvps = dbCtx.tblDVPTests.Where(x => x.DVPID == 2176);
// these 2 following if conditions doesnt bring correct result sets
if (dvpMasterPhaseId.HasValue)
{
dvps = dvps.Where(x => x.tblDVPPhases.All(p => p.DVPMasterPhaseID ==255));
}
if (dvpMasterVariantId.HasValue)
{
dvps = dvps.Where(x => x.tblDVPPhases.All(p => p.tblDVPVariants.All(v=>v.DVPMasterVariantID==681)));
}
}
UPDATE
I want this following query to be written in LINQ and if one of you guys tell me what was wrong with the LINQ query above that will be great.
Following expression
dvps = dvps.Where(x => x.tblDVPPhases.All(p => p.DVPMasterPhaseID ==255));
Should be equivalent to this SQL Query.
select * from tblDVPTest
inner join tblDVPPhase on tblDVPTest.DVPTestID=tblDVPPhase.DVPTestID
where dvpid=2176 and tblDVPPhase.DVPMasterPhaseID=255
Here is with both condition
** LINQ**
dvps = dvps.Where(x => x.tblDVPPhases.All(p => p.tblDVPVariants.All(v=>v.DVPMasterVariantID==681)));
Should be equivalent to this SQL Query.
select * from tblDVPTest
inner join tblDVPPhase on tblDVPTest.DVPTestID=tblDVPPhase.DVPTestID
inner join tblDVPVariant on tblDVPPhase.DVPPhaseID=tblDVPVariant.DVPPhaseID
where dvpid=2176 and tblDVPPhase.DVPMasterPhaseID=255 and tblDVPVariant.DVPMasterVariantID=681
This code is adding two conditional filters (where) to the original query. Each extra filter limits the items included in the result.
In case the variable dvpMasterPhaseId is non-null the query only includes the items for which All related DPVPhases have a dvpMasterVariantId of 255
If the variable dvpMasterVariantId is non-null the query only includes the items for which All the related Variants of All the related Phases have a DVPMasterVariantID of 681.
The SQL code will not just show the DPV Tests for which ALL Phases / Variants meet these conditions, but where ANY of the Phases / Variants meet these conditions. Moreover it will return a separate row for each Test / Phase / Variant that meets these conditions
Related
Well I've got a query
var grouped = from a in query
group a.Payment by a.PaymentRecieverId
into g
select g;
query is a IQueryable of new { Payment payment, int PaymentRecieverId }
How can I convert this method expression to query?
If I understand correctly, the question is how to map group a.Payment part.
The GroupBy method has several overloads, you need the one that allows you to specify elementSelector:
var grouped = query.GroupBy(a => a.PaymentRecieverId, a => a.Payment);
If you mean lambda syntax, then it will be:
var grouped = query.GroupBy(x => x.PaymentRecieverId);
If you mean SQL query, then just hover your mouse on query object while debugging:
I have a linq query which I want to add some additional, optional WHERE conditions to using LinqKit Predicate Builder. However, I an struggling to get the additional predicate to work
This is my initial query:
var query = (from OP in ctx.OrganisationProducts
where OP.OrganisationID == orgID
orderby OP.Product.Name, OP.Product.VersionName
select OP).Include("Product");
As you can see, there is JOIN in there.
I then wish to add additional predicates if required:
if(!includeDisabledP42Admin || !includeDisabledOrgAdmin)
{
var pred = PredicateBuilder.True<OrganisationProduct>();
if (!includeDisabledP42Admin)
pred.And(op => op.Enabled);
if (!includeDisabledOrgAdmin)
pred.And(op => op.AccessLevel == "NA" || op.AccessLevel == "NU");
query = query.Where(pred);
}
However, the generated SQL is unchanged and the query returns the same number of rows.
I thought I might have had to do the Expand conversion as so:
query = query.AsExpandable().Where(pred);
But this causes a runtime error.
I think the issue is the fact that I am adding the predicate to a query that is already no longer a pure OrganisationProduct object, however I would like advise on how I insert my predicate at the right place.
Thanks and all :-)
You have to assign the return value of And to the predicate:
pred = pred.And(op => op.Enabled);
Side note: you may like this predicate builder that works without Expand/AsExpandable, but has the same syntax.
Trying to add a second where clause to a linq expression but it won't register.
var query = _dbSetBookedResource.AsQueryable<Resource>();
var resources = (from Resource in query where Resource.DateFrom == date select Resource)
if(true)
{
resources.Where(b => b.MemberId == currentUserId);
}
For some reason the second where clause won't register.
For some reason the second where clause won't register.
That's because you're not using the return value anywhere. That's just setting up a query, but then ignoring it. No LINQ methods change the value they're called on - instead they create a new query which has the appropriate filtering, projection etc.
You need:
resources = resources.Where(b => b.MemberId == currentUserId);
Also note that your initial query could be written more simply as:
var resources = query.Where(r => r.DateFrom == date);
Query expressions are overkill when all you want is a simple filter or projection.
See two functionally identical queries below, sql and lambda version:
from a in Lines.AsEnumerable()
where a.LineId == SomeGuid
select a
-
Lines.AsEnumerable()
.Where(a => a.LineId == SomeGuid)
.Select(a => a)
Both queries will be translated into SQL that doesn't have WHERE statement, something like
SELECT * FROM Line
In lambda, I can conveniently put AsEnumerable after Where clause and resulting SQL will have WHERE clause. So, lambda query would be like:
Lines
.Where(a => a.LineId == SomeGuid)
.AsEnumerable()
.Select(a => a)
And resulting SQL is SELECT * FROM Line WHERE LineId = #param
Question:
How do I do this using Linq SQL syntax? In other words, I would like my resulting SQL statement to have WHERE clause. I want to avoid pulling all records from the table Line. I tried to put AsEnumerable on different places within the query, but I failed to make it work.
EDIT:
In simple statements putting AsEnumerable on the end will work, but if you use projection, then EF complains (NotSupported Exception: Complex type can't be constructed ...)
So,
(from a in Lines
where a.LineId == SomeGuid
select new Line
{
LineId = a.LineId
}).AsEnumerable()
Won't work
You will simply do this:
var query (from a in context.Lines
where a.LineId == SomeGuid
select a).AsEnumerable();
But in most cases this is not needed. It makes your query enumerable but does not execute your query. The query will be executed only when iterating.
Btw. .Select(a => a) in your examples is not needed because it happens automatically.
Edit:
Linq-to-entities forbid projecting to mapped types so as I mentioned it comment you must first project to anonymous type, call AsEnumerable and project to the real mapped type.
var query = (from a in Lines
where a.LineId == SomeGuid
select new {
LineId = a.LineId
}).AsEnumerable()
.Select(a => new Line { LineId = a.LineId });
In this case you even don't need anonymous type because you can select a.LineId directly.
I couldn't get last articles of every writers in this statement.
List<Editor> lstEditors = dataContext.GetTable<Editor>().Where(t => t.M_Active).Select(t => t).ToList();
var lstArticles = from article in DAO.context.GetTable<Article>().ToList()
join editor in lstEditors on article.RefEditorId equals editor.EditorId
select
new
{
article.M_ArticleId,
article.M_Subject,
article.M_Text,
editor.M_EditorId,
editor.M_Member.M_EditorPicture,
M_NameSurname = editor.M_Member.M_Fname + " " + editor.M_Member.M_Lname
};
Be careful, your query is fetching all the contents of both the Editor and the Yazi tables and then performs Linq-to-Objects on it.
I'm not sure what you ask exactly either, do you want to obtain the list of all writers (editors) along with the last article of each one of these writers?
Do you want to get the writers that did not write any articles yet also?
Edit:
explanation of methods causing an immediate query
Any time you call one of the methods listed below on an IQueryable object (tables or other queries), it performs the actual query to SQL server:
ToList(), ToArray(), ToLookup(), ToDictionay()
Count(), Sum(), Avg(), Aggregate(), Min(), Max()
First(), FirstOrDefault(), Last(), LastOrDefault()
getting last article written by each writer
//create a subquery that returns an editor and its last article date
var editorLastArticleDates =
from article in DAO.context.GetTable<Article>()
group article by article.RefEditor into g
let lastArticleDate= g.Max(x => x.Date)
select new
{
Editor = g.Key,
LastArticleDate = lastArticleDate,
};
//Note: We did not do a ToList() here so the query is not executed
// The editorLastArticleDates object is a IQueryable<>
var query =
from article in DAO.context.GetTable<Article>()
join editorLastArticleDate in editorLastArticleDates
on new { article.Editor, article.Date } // 1
equals new { editorLastArticleDate.Editor, // 2
Date = editorLastArticleDate.LastArticleDate } // 3
select new
{
article.M_ArticleId,
article.M_Subject,
article.M_Text,
article.RefEditor.M_EditorId,
article.RefEditor.M_Member.M_EditorPicture,
M_NameSurname = article.RefEditor.M_Member.M_Fname + " "
+ article.RefEditor.M_Member.M_Lname,
};
//Note: We did not do a ToList() yet so the query is not executed
// The query object is a IQueryable<>
Console.WriteLine(query.ToString()); //Displays SQL query on the console
var results = query.ToList(); // SQL query is executed on this line.
In the code above, I left some remarks on things I had problems with:
When using join, the section between new and equals access only variables declared before the join keyword while the section after the equals keyword has access to the variable defined between join and in.
When writing your join condition, make sure you use equals and not ==.
When using new { XXX, YYY } syntax in your join condition, you declare anonymous types. If the property names are not identical on both sides, it will not compile. In order to have identical property names in this sample, I added the Date = before my value.
By the way, you should use LinqPad to test your queries, it is really a nice tool.