How can I use a method withing a linq query? - c#

Here is my query
return (from l in Context.DctLink
join t in Context.DctTabel on l.BType equals t.DocType
join t2 in Context.DctTabel on l.TabelNr equals t2.TabelNr
where l.AType == docType || l.AType == 0
select new { t.TabelNr, t2.Naam, t.Titel })
.Union(from l in Context.DctLink
join t in Context.DctTabel on l.AType equals t.DocType
join t2 in Context.DctTabel on l.TabelNr equals t2.TabelNr
where l.BType == docType || l.BType == 0
select new { t2.TabelNr, t2.Naam, t.Titel })
.Join(Context.TimIcon.Where(q => q.Timweb && q.ShowId.ToInt32() > 0),
x => x.TabelNr,
y => y.TabelNr,
(x, y) => new LookupItem
{
Id = x.TabelNr,
Name = x.Titel,
Tag = x.Naam
}).ToList();
I want to be able to do this q.ShowId.ToInt32() > 0. But I get a System.Unsupported Exception. Isn't this possible in a link query or am I just overlooking something simple
Thanks in advance

You need to fetch the data from db using AsEnumerable or ToList, then you can use any method you want. Otherwise it's not possible because EF Query Provider can't know how to translate your method into SQL.

It depends on your LINQ provider. LINQ to Objects supports pretty much anything. The one you're using (LINQ to Entities or LINQ to SQL or something similar) doesn't support everything, because it needs to understand your expression and translate it to SQL (it can't do that with any kind of expression).
The simplest way to fix this is to call AsEnumerable() at some point, in order to convert the sequence (up to that point) to an in-memory sequence, so you'll fall back to LINQ to Objects and you can perform the (previously unsupported) logic on it.

Related

Equivalent LINQ query for SQL query not resulting in expected results

I am trying to write a LINQ query equivalent to below SQL
SELECT DISTINCT m.*,rm.RoleId FROM dbo.Menu m
INNER JOIN dbo.RoleMenu rm on m.Id=rm.MenuId
INNER JOIN dbo.RoleUser ru on rm.RoleId=ru.RoleId
WHERE ru.UserName='dd#dd.com' and m.Url='/dashboard#/pm'
I came with the below query which is not returning the expected output
var auth = _context.RoleUsers.Where(
x => x.Role.MenuRoles.FirstOrDefault().Menu.Url == pagePermissions.Url
&& x.UserName == pagePermissions.UserName).Count()
May I know a better way to do this?
Your sql looks at all the menus related to a role user, but your Linq is only looking at the first one. I think you want x.Role.MenuRoles.Any(mr => mr.Menu.Url == pagePermissions.Url). But then you're also doing a Count on the matching users instead of selecting the menus that match that url. A closer translation would be.
var results = (from m in _context.Menus
from rm in m.RoleMenus
from ru in rm.RoleUsers
where m.Url == pagePermissions.Url
&& u.UserName == pagePermissions.UserName
select new { Menu = m, rm.RoleId }).Distinct();
You may have to adjust some of the navigation properties as I was just guessing at them. They usually are pluralizations of the tables, but I see in your Linq that you have MenuRoles instead of RoleMenus.

how can I implement CASE WHEN with LINQ?

I wrote a T-SQL code which has used case when in select scope. We couldn't use t-sql or store procedure in application, because of that I need to convert follong code to LINQ. Is there any way to change this code to linq quickly?
SELECT
T.TaskID,
SUM(CASE WHEN T.LogDate<#fromDate AND T.TaskStatusID=2 THEN ISNULL(DA_CHILD.Score,0)*(T.DoneScore/100) ELSE 0 END) PreAmount,
SUM(CASE WHEN T.LogDate>=#fromDate AND T.LogDate<=#toDate AND T.TaskStatusID=2 THEN ISNULL(DA_CHILD.Score,0)*(T.DoneScore/100) ELSE 0 END) CurAmount
FROM
NetTasks$ T
INNER JOIN NetDeviceActions DA ON DA.DeviceActionID=T.DeviceActionID
LEFT JOIN NetFinancialInfoDetail FID ON FID.TaskID=T.TaskID
INNER JOIN NetActionParents AP ON AP.ParentID=DA.ActionID
INNER JOIN NetDeviceActions DA_CHILD ON DA_CHILD.ActionID=AP.ChildID AND
DA_CHILD.DeviceID=DA.DeviceID AND
DA_CHILD.ContractInfoID=DA.ContractInfoID
WHERE
T.ParentTaskID = 0 AND
T.FinishDate<=#toDate AND
DA.ContractInfoID=9
GROUP BY
T.TaskID, T.DoneScore,T.FinishDate
In LINQ you can use C# statements so CASE WHEN is actually not hard.
Assuming you have finished all the joining into a query object called values, you can use something like below for the grouping and select:
var q = from a in values
group a by new {a.TaskID, a.DoneScore, a.FinishDate} into g
select new {
g.Key.TaskID,
PreAmount = g.Where(x => x.LogDate < fromDate && x.TaskStatusID == 2 && x.DA_CHILD.HasValue).Select(x => x.DoneScore).Sum(),
CurAmount = g.Where(x => x.LogDate >= fromDate && x.LogDate < toDate && x.TaskStatusID == 2 && x.DA_CHILD.HasValue).Select(x => x.DoneScore).Sum()
};
And of course, a friendly reminder, left joining in LINQ is very tedious.
Are you just looking for a simple where clause in your statement? (Though I admit this LINQ query is not going to be particularly simple.)
https://msdn.microsoft.com/en-us/library/bb397927.aspx
I advise building it up slowly.
With such good looking SQL, would you not be happier using QueryFirst and forgetting about Linq? You run your SQL directly in your C# app.
disclaimer : I wrote QueryFirst

Linq IN Clause in Where

I want to know how to use IN clause in Linq. Here is my Code :-
int empCount = ctx.tblEmpTran
.Count(
e => e.Id == Id &&
e.Month == selectedMonth &&
e.Year == selectedYear &&
e.employeeId.contains()
);
The Following query is supposed to be in IN
SELECT A.Id FROM dbo.EmployeeDetail A WHERE A.CompanyId = 1 AND A.COLS > 0
In the above code, contains method do not popup in intellisense.
This is because you are trying to convert from SQL to Linq, and you couldn't try a worse approach.
You should try to write your LINQ query starting from what you need it to do, forgetting SQL altogether.
In Linq there is no "IN" operator, to achieve the same thing you take your collection and check if it Contains the value.
So in your scenario you should simply generate your collection of valid values and then in your query do:
myCollection.Contains(e.employeeId)
It is "collection CONTAINS value" the logic, not "value is found IN collection". Again if you insist to start from SQL when using Linq you will always incur in this kind of problems.
Check Albahari tutorial on how to approach Linq correctly and your productivity will skyrocket.
You should create a collection of employee IDs that you want to check, and the code would be
employees.contains(e.employeeId)
Instead of this e.employeeId.contains(), you should use this:
listOfIds.Contains(e.employeeId)
where listOfIds would be a list of int, List<int> and would contain the ids you would place between the parentheses after IN(...).
considering that you have a tblEmployeeDetail in the same DbSet and them having a relation through employeeId you can write you query like.
var q = from e in ctx.tblEmployeeDetail where e.Transactions.Any(t => t.Month == selectedMonth &&
t.Year == selectedYear);
int empCount = q.Count();
this is pseudo-code but this is how you would use the LINQ effectively, (Exists is better than In check)

comparison operator not supported for type int[] - linq to sql

Here is the problematic line:
var originalSummaryCandidates =
(from a in masterDB.tbl_thirty_second_summaries_multi_variant_associations
join d in masterDB.tbl_thirty_second_summaries_multi_variants on a.ThirtySecSummaryId equals d.ThirtySecondSummaryId_this
where d.DrugId == drugId &&
variantGenotypeIds.Contains(new int[] {a.VariantId, a.GenotypeId})
select d.ThirtySecondSummaryId_this)
.Distinct()
.ToList();
variantGeotpeIds is of type List<int[]>. Both a.VariantId and a.GenotypeId are of type int.
I cannot figure out why it why it will not do the comparison. Is this a deferred execution issue? It doesn't seem like it should be...
Thanks in advance.
List<T>.Contains only takes a single parameter of type T. In your case, T is Int32 but you're passing in a Int32[].
If you want to check that both values are in the list, you have to break the calls apart:
where d.DrugId == drugId &&
variantGenotypeIds.Contains(a.VariantId) &&
variantGenotypeIds.Contains(a.GenotypeId)
EDIT
If variantGenotypeIds is actually a List<Int32[]>, then there's another issue. LINQ to SQL will try to convert your query into its SQL equivalent. In this case, there's no way to translate your query into SQL so LINQ to SQL will throw an Exception.
If you really need to query this way, you'll have to read the records into memory first and then query using LINQ to Objects (which may or may not be a big deal depending on how many rows you are reading):
var query =
from a in masterDB.tbl_thirty_second_summaries_multi_variant_associations
join d in masterDB.tbl_thirty_second_summaries_multi_variants
on a.ThirtySecSummaryId equals d.ThirtySecondSummaryId_this
where d.DrugId == drugId
select new { a, d }
var originalSummaryCandidates =
(from q in query.AsEnumerable()
where variantGenotypeIds.Contains(new [] { q.a.VariantId, q.a.GenotypeId})
select d.ThirtySecondSummaryId_this)
.Distinct()
.ToList();
Array comparison uses reference equality by default. It's possible that linq-to-sql just tries to translate that into SQL that compares the values, but you'd have to look at the generated SQL to be sure. Another option would be to use Any instead:
where d.DrugId == drugId &&
variantGenotypeIds.Any(v => v[0] == a.VariantId && v[1] == a.GenotypeId)
but I'm not sure if Linq-to-Sql will be able to translate that to the correct SQL either. Another option would be to project the List` to a > and then do a string comparison:
variantGenotypeStrings = variantGenotypeIds.Select(v => string.Format("{0}|{1}", v[0],v[1]);
var originalSummaryCandidates =
(from a in masterDB.tbl_thirty_second_summaries_multi_variant_associations
join d in masterDB.tbl_thirty_second_summaries_multi_variants on a.ThirtySecSummaryId equals d.ThirtySecondSummaryId_this
where d.DrugId == drugId &&
variantGenotypeStrings.Contains(string.Format("{0}|{1}", a.VariantId, a.GenotypeId))
select d.ThirtySecondSummaryId_this)
.Distinct()
.ToList();

using "greater than or equal" operator in linq join operation [duplicate]

I had tried to join two table conditionally but it is giving me syntax error. I tried to find solution in the net but i cannot find how to do conditional join with condition. The only other alternative is to get the value first from one table and make a query again.
I just want to confirm if there is any other way to do conditional join with linq.
Here is my code, I am trying to find all position that is equal or lower than me. Basically I want to get my peers and subordinates.
from e in entity.M_Employee
join p in entity.M_Position on e.PostionId >= p.PositionId
select p;
You can't do that with a LINQ joins - LINQ only supports equijoins. However, you can do this:
var query = from e in entity.M_Employee
from p in entity.M_Position
where e.PostionId >= p.PositionId
select p;
Or a slightly alternative but equivalent approach:
var query = entity.M_Employee
.SelectMany(e => entity.M_Position
.Where(p => e.PostionId >= p.PositionId));
Following:
from e in entity.M_Employee
from p in entity.M_Position.Where(p => e.PostionId >= p.PositionId)
select p;
will produce exactly the same SQL you are after (INNER JOIN Position P ON E..PostionId >= P.PositionId).
var currentDetails = from c in customers
group c by new { c.Name, c.Authed } into g
where g.Key.Authed == "True"
select g.OrderByDescending(t => t.EffectiveDate).First();
var currentAndUnauthorised = (from c in customers
join cd in currentDetails
on c.Name equals cd.Name
where c.EffectiveDate >= cd.EffectiveDate
select c).OrderBy(o => o.CoverId).ThenBy(o => o.EffectiveDate);
If you have a table of historic detail changes including authorisation status and effective date. The first query finds each customers current details and the second query adds all subsequent unauthorised detail changes in the table.
Hope this is helpful as it took me some time and help to get too.

Categories

Resources