"Case" in the order-by statement - c#

Hello I have the following linq statement:
IEnumerable<TabTransaktion> allTransactions
= TabTransaktions1.Union(TabTransaktions2)
.Where(trans => trans.TabVorgang != null).
.OrderBy(tran => tran.TabVorgang.Wirkdatum)
.OrderByDescending(trans2 => trans2.TabVorgang.ID);
But I want the second order by descending when only trans2.TabVorgang.ID equals to 0. So I need a "case" in "order by clause" for LinQ. A LinQ equivalent of something like this:
SELECT BusinessEntityID, SalariedFlag
FROM HumanResources.Employee
ORDER BY CASE SalariedFlag WHEN 1 THEN BusinessEntityID END DESC
,CASE WHEN SalariedFlag = 0 THEN BusinessEntityID END;
GO
I would appreciate any help.

Assuming SalariedFlag is a bool (in SQL of type bit), the two ordering expressions are exclusively mutual. In other words, the main query can be separated into two disjunctive queries and the final result is the union of them:
IEnumerable<TabTransaktion> mainQuery
= TabTransaktions1.Union(TabTransaktions2)
.Where(trans => trans.TabVorgang != null);
var queryOne = mainQuery.Where(p=>p.SalariedFlag ==1)
.OrderByDescending(tran => tran.BusinessEntityID );
var queryTwo = mainQuery.Where(p=>p.SalariedFlag ==0)
.OrderBy(tran => tran.BusinessEntityID);
var finalResult = queryOne.Union(queryTwo);

Related

LINQ query to merge multiple rows

I am trying to convert an SQL query that works, to LINQ equivalent.
Here is the query.
SELECT REPORT_NUMBER,
case when count(distinct STATE) > 1 then 'PENDING'
else case when max(STATE) = 'REPORTED' then 'REPORTED'
else 'PENDING' end end status,
max(REPORT_YEAR)
FROM SAMPLE
GROUP BY REPORT_NUMBER
ORDER BY max(REPORT_YEAR) DESC
So far I created LINQ query that needed a help.
var sums = from foo in db.SAMPLEs
group foo by foo.REPORT_NUMBER into groupings
orderby groupings.Key ascending
select new ReportListModel
{
ReportNbr = groupings.Key,
ReportYear = groupings.Max(g => g.REPORT_YEAR),
ReportSt = groupings.Max(g => g.STATE)
};
Using groupings.Max(g => g.STATE) gives me correct amount of records, but obviously gives me incorrect field result.
How can I create case statement as in SQL query?
You can use inline-if operator like so:
var sums = from foo in db.SAMPLEs
group foo by foo.REPORT_NUMBER into groupings
orderby groupings.Key ascending
select new ReportListModel
{
ReportNbr = groupings.Key,
ReportStatus =
groupings.Select(x => x.STATE).Distinct().Count() > 1 ?
"PENDING" : (
groupings.Max(g => g.STATE) == "REPORTED" ?
"REPORTED" : "PENDING"
)
};

different results between Linq and SQL

i don't know why i get different results between this SQL and LINQ
Could you like to tell me why...?
SQL:
select distinct top 50 (id) as d_id
from talbe1
where id<>-1
order by d_id asc;
Linq:
IList<int> myResults =
(from t in dbconn.table1
where t.id != -1
orderby t.id ascending
select t.id
).Distinct().Take(50).ToList();
int callCnt = 0;
foreach (int row in myResults)
{
callCnt++;
Console.WriteLine(callCnt.ToString() + " " + row.ToString() );
}
The SQL get the results i want,
but the Linq result is like :
1 72662
2 84945
3 264577
4 77655
5 71756
6 76899
7 76719
8 77669
9 152211
10 79168
11 72334
12 71399
13 246031
14 80748
15 77715
.......
This is a limitation of LINQ to SQL, where the OrderBy() must occur after the Distinct(), try this:
IList<int> myResults =
(from t in dbconn.table1
where t.id != -1
select t.id
).Distinct().OrderBy(t => t).Take(50).ToList();
The problem is the way that the Distinct() method works. Unfortunately it can (and usually does) change the order of the items in the list. You need to order the list after calling Distinct().
Try this:
IList<int> myResults =
(
from t in dbconn.table1
where t.id != -1
select t.id
).Distinct().OrderBy(i => i).Take(50).ToList();
Try
var myResults = dbconn.Table1.Where(e => e.id != -1).Select(e => e.id).Distinct()
.OrderBy(t => t).Take(50).ToList();

Can you use a CASE statement with OrderBy in an LINQ to Entities query?

I'm wonder if someone can transform the SQL below to a LINQ to Entities query
SELECT Name, IsEmployee, IsQualityNetwork
FROM Person
ORDER BY CASE WHEN IsQualityNetwork = 1 or IsEmployee = 1 THEN 0 ELSE 1 END, Name
I tried using Linq Dynamic but when this code is executed:
var p = ctx.People
.OrderBy("CASE WHEN IsQualityNetwork = 1 or IsEmployee = 1 THEN 0 ELSE 1 END")
.OrderBy(e => e.Name);
I get the exception:
{"No property or field 'CASE' exists in type 'Person'"}
var p = ctx.People.OrderBy(p => (p.IsQualityNetwork == 1 || p.IsEmployee == 1) ? 0 : 1)
.ThenBy(p => p.Name);
Here's a translation of your SQL to LINQ.
var query = from p in ctx.People
let order = p.IsQualityNetwork || p.IsEmployee ? 0 : 1
orderby order, p.Name
select new
{
p.Name,
p.IsEmployee,
p.IsQualityNetwork,
}
I've used the fluent query syntax so I could show you the let keyword. let allows you to declare a range variable that can then be reused in your query, this can be very useful if you've got a conditional that gets used in a lot of places, or if you need to chain multiple conditionals.

EF, how to increase query performance

i have about 1 million data in my database(MySQL)
and there's a advancedSearch function which is very slow(more than 30 sec), because the SQL EntityFramework generated is not very good, SQL:
SELECT
`Project1`.*
FROM
(
SELECT
`Extent1`.*
FROM `tnews` AS `Extent1`
WHERE `Extent1`.`Region` = 'Americas(2)'
) AS `Project1`
ORDER BY
`Project1`.`PnetDT` DESC LIMIT 0,20
C# function:
private List<CNNews> AdvancedSearchAndPage(int pagenum, int pagesize,
AdvSearchArgs advArgs)
{
IQueryable<CNNews> result = _dbRawDataContext.CNNews.
OrderByDescending(n => n.PnetDT);
if (!string.IsNullOrWhiteSpace(advArgs.Feed))
{
result = result.Where(news => news.Feed == advArgs.Feed);
}
if (!string.IsNullOrWhiteSpace(advArgs.PNET))
{
result = result.Where(news=>news.PNET == advArgs.PNET);
}
if (!string.IsNullOrWhiteSpace(advArgs.ProdCode))
{
result = (from news in result
where news.ProdCode == advArgs.ProdCode
select news);
}
if (!string.IsNullOrWhiteSpace(advArgs.Code))
{
result = (from news in result
where news.Code == advArgs.Code
select news);
}
if (!string.IsNullOrWhiteSpace(advArgs.BegineDate))
{
var begin = Convertion.ToDate(advArgs.BegineDate);
var end = Convertion.ToDate(advArgs.EndDate);
result = (from news in result
where news.PnetDT >= begin && news.PnetDT < end
select news);
}
if (!string.IsNullOrWhiteSpace(advArgs.Region))
{
result = result.Where(x => x.Region == advArgs.RegionName);
}
var pagedList = result.
Skip(pagenum * pagesize).
Take(pagesize);
return pagedList.ToList();
}
if the SQL format like this, it will very fast:
SELECT
*
FROM `tnews` AS `Extent1`
WHERE `Extent1`.`Region` = 'Americas(2)'
ORDER BY
`PnetDT` DESC LIMIT 0,20
You can execute your own SQL directly off the DbSet and get all the benefits of EF, see
http://msdn.microsoft.com/en-us/library/system.data.entity.dbset.sqlquery(v=vs.103).aspx
Also other ways, see these answers for more details
Is it possible to run native sql with entity framework?
The LINQ that generated your query looks something like this:
IQueryable<CNNews> result = _dbRawDataContext.CNNews
.OrderByDescending(n => n.PnetDT)
.Where(x => x.Region == advArgs.RegionName)
.Skip(pagenum * pagesize)
.Take(pagesize);
You tell LINQ to select all items and order them. Then you tell it to take a subset of that. The SQL looks exactly like what you have specified, I would say.
If you rearrange your code somewhat so that the Where() call is before the OrderByDescending() call I think you might get better SQL:
IQueryable<CNNews> result = _dbRawDataContext.CNNews
.Where(x => x.Region == advArgs.RegionName)
.OrderByDescending(n => n.PnetDT)
.Skip(pagenum * pagesize)
.Take(pagesize);
Also, I don't know if changing order of OrderByDescending() and Skip()/Take() would give different results.
(Disclaimer: I haven't tested it)

Use Any() and Count() in Dynamic Linq

I am trying to write dynamic Linq Library query to fetch record on condition,
Customers who has order count is greater than 3 and ShipVia field equal 2.
Below is my syntax what i have tried.
object[] objArr = new object[10];
objArr[0] = 1;
IQueryable<Customer> test = db.Customers.Where("Orders.Count(ShipVia=2)", objArr);
and
IQueryable<Customer> test = db.Customers.Where("Orders.Any(ShipVia=2).Count()", objArr);
But both are not working. In second query Any returns true so it won't work with Count.
Suggest me a way to implement this.
If you HAVE to use Dynamic Linq, your query should look like that:
db.Customers.Where("Orders.Count(ShipVia == 2) > 3");
How about something like this.
IQueryable<Customer> test = db.Customers.Where(c => c.Orders.Where(o => o.ShipVia ==2).Count() >2);
var grp = db.Customers.Where("ShipVia=2").GroupBy("ShipVia");
var test = from a in grp
where a.Count() > 3
select a.Key;
IQueryable<Customer> test =
from c in db.Customers
from o in c.Orders
where o.ShipVia == 2 // NOTE you need == not = for compare
group c by c into grp
select new {customer = grp.key, ordercount = grp.Count() };
Untested but I believe this should do it all in one statement, assuming Orders are a collection within Customer.
Note that your single = in your where clause is very dangerous as it'll assign 2 to all shipvias instead of test (==)

Categories