Grouping on virtual (predefined) column in linq - c#

I am trying to write a linq query for one of my dashboard which retrieves data based on some conditions. I want to display records count based on the different status available in my table.
Following is the SQL query in which I am trying to convert into Linq.
select count(id) cnt, 'Available' label from table where date = sysdate
Above query is returning below result in DB IDE. This is the result I want with linq
cnt label
0 Available
I've tried with following linq query but it is returning 0 count and hence result is not being retrieved.
var data = (from a in context
where a.date = System.DateTime.Now
group a in a.id into g
select new {
cnt = g.Count(),
label = 'Available'
}).ToList();
How do I achieve above mentioned result in linq. Your help will be appreciated.
Thanks
-------------EDIT----------------
Updated LINQ query
var data = (from a in context.TableA
where a.id = uniqueID
group a in a.id into g
select new {
cnt = g.Count(),
label = 'Available'
}).Concat(from a in context.TableB
where a.id = uniqueID
group a in a.id into g
select new {
cnt = g.Count(),
label = 'WIP'
}).ToList();

To count the number of elements matching a predicate in a linq query simply use the where clause:
var results =
from a in context
where a.date.Date == DateTime.Now.Date
&& a.id == someIdHere
select a;
var data = new {
count = results.Count(),
label = "Available"
};
Or, in extension method syntax (which I prefer):
var results = context.Where(a => a.date.Date == DateTime.Now.Date && a.id == someIdHere);
var data = new {
count = results.Count(),
label = "Available"
};
Also be careful when comparing a DateTime object with regards to what results you desire; comparing DateTime.Now to a date will likley return false since it will compare the time code as well, use the DateTime.Date property to obtain only the date from the object for the purposes of comparison.

Related

unable to create a constant value of type anonymous type only primitive types

Using Entity Framework Version=6.0.0.0 to get to get common id and orderid as shown below.
var dt1 = from p in dt.AsEnumerable()
select new
{
Id = p.Field<int>("Id"),
OrderId = p.Field<int>("OrderId")
};
var dt2 = (from order in db.Orders
select new
{
order.Id,
order.OrderId
}).ToList();
var intersect = dt1.Intersect(dt2);
Based on the list of values in intersect. I need to select all the values from Orders Table.
Trying to used code getting error "unable to create a constant value of type anonymous type only primitive types"
var result= (from a in sync.Orders
where intersect.Any(b => a.Id == b.Id && a.OrderId == b.OrderId)
select a).ToList();
You are trying to "join" an EF query with an in-memory data set, which does not work because there's not a way to embed the list and the lookup in SQL. One option is to pull the entire table into memory with AsEnumerable:
var result= (from a in sync.Orders.AsEnumberable
where intersect.Any(b => a.Id == b.Id && a.OrderId == b.OrderId)
select a).ToList();
Another option is to concatenate the Id and OrderId into one value and use Contains since that can be translated to an IN clause in SQL:
var lookup = intersect.Select(i => i.Id + "-" + i.OrderId).ToList();
var result= (from a in sync.Orders
where lookup.Contains(a.Id + "-" + a.OrderId)
select a).ToList();

How do I convert this tSQL statement to LINQ using group by in a sub query

I have the following MSSQL query I am trying to convert to LINQ. I am using entity framework with the following syntax to get at the data.
var rv = (from i in DC.TableA select i).ToList();
This is the sql I want to write a C# LINQ query for but I cannot figure it out. Can someone help?
select BTO.*
from TableA BTO
join
(
select eqnum, max(testdate) as testdate
from TableA BTO1
where
BTO1.eqnum in ('M0435', 'Z0843') and
BTO1.testdate <= '2008-06-01'
group by eqnum
) T1
on
T1.eqnum = BTO.eqnum and
T1.testdate = BTO.testdate
order by EqNum;
I think there is opportunity to rewrite your query, but for information purposes I rewrote your sql into linq verbatim.
If you explain what you are trying to achieve we can provide alternative sql / linq
var eqnums = new[] { "M0435", "Z0843" };
var testdate = "2008-06-01";
var query = from bto in DC.TableA
join t1 in (
from bto1 in DC.TableA
where eqnums.Contains(bto1.eqnum) &&
bto1.testdate.CompareTo(testdate) <= 0
group bto1 by bto1.eqnum into g
select new
{
eqnum = g.Key,
testdate = g.Max(x => x.testdate)
}
) on new { bto.eqnum, bto.testdate } equals new { t1.eqnum, t1.testdate }
orderby bto.eqnum
select bto;

left join in Linq query

I'm trying to do a left join, not an inner join in a linq query. I have found answers related to using DefaultIfEmpty() however I can't seem to make it work. The following is the linq query:
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id
where a.Table1_id == id
orderby a.sort descending
group e by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
The query only gives me the rows from table 1 that have a corresponding record in table 2. I would like every record in table 1 populated into MyObject and a list of 0-n corresponding records listed in manySubObjects for each MyObject.
UPDATE:
I tried the answer to the question that is a "possible duplicate", mentioned below. I now have the following code that does give me one record for each item in Table1 even if there is no Table2 record.
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id into j1
from j2 in j1.DefaultIfEmpty()
where a.Table1_id == id
orderby a.sort descending
group j2 by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
However, with this code, when there is no record in table2 I get "manySubObject" as a list with one "SubObject" in it with all null values for the properties of "SubObject". What I really want is "manySubObjects" to be null if there is no values in table2.
In reply to your update, to create the null listing, you can do a ternary in your assignment of manySubObjects.
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects =
(from g in ga select g).FirstOrDefaut() == null ? null :
(from g in ga select new SubObject {
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
Here is a dotnetfiddle that tries to do what you're attempting. https://dotnetfiddle.net/kGJVjE
Here is a subsequent dotnetfiddle based on your comments. https://dotnetfiddle.net/h2xd9O
In reply to your comments, the above works with Linq to Objects but NOT with Linq to SQL. Linq to SQL will complain that it, "Could not translate expression ... into SQL and could not treat as a local expression." That's because Linq cannot translate the custom new SubObject constructor into SQL. To do that, you have to write more code to support translation into SQL. See Custom Method in LINQ to SQL query and this article.
I think we've sufficiently answered your original question about left joins. Consider asking a new question about using custom methods/constructors in Linq to SQL queries.
I think the desired Result that you want can be given by using GroupJoin()
The code Below will produce a structure like so
Field1, Field2, List < SubObject > null if empty
Sample code
var query = dc.Table1.Where(x => Table1_id == id).OrderBy(x => x.sort)
.GroupJoin(dc.Table2, (table1 => table1.Table1_id), (table2 => table2.Table2_id),
(table1, table2) => new MyObject
{
field1 = table1.Field1,
field2 = table1.Field2,
manySubObjects = (table2.Count() > 0)
? (from t in table2 select new SubObject { fielda = t.fielda, fieldb = t.fieldb}).ToList()
: null
}).ToList();
Dotnetfiddle link
UPDATE
From your comment I saw this
ga.Select(g = > new SubObject(){fielda = g.fielda, fieldb = g.fieldb})
I think it should be (depends on how "ga" is built)
ga.Select(g => new SubObject {fielda = g.fielda, fieldb = g.fieldb})
Please update your question with the whole query, it will help solve the issue.
** UPDATE BIS **
sentEmails = //ga.Count() < 1 ? null :
//(from g in ga select g).FirstOrDefault() == null ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Should be:
sentEmails = //ga.Count() < 1 ? null :
((from g in ga select g).FirstOrDefault() == null) ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Checks if the group has a First, if it doesn't the group doesn't have any records so the Action.Name for a Time Stamp has no emails to send. If the First isn't null the loop throw the group elements and create a list of Email,
var results =
(
// Use from, from like so for the left join:
from a in dc.Table1
from e in dc.Table2
// Join condition goes here
.Where(a.Id == e.Id)
// This is for the left join
.DefaultIfEmpty()
// Non-join conditions here
where a.Id == id
// Then group
group by new
{
a.Field1,
a.Field2
}
).Select(g =>
// Sort items within groups
g.OrderBy(item => item.sortField)
// Project required data only from each item
.Select(item => new
{
item.FieldA,
item.FieldB
}))
// Bring into memory
.ToList();
Then project in-memory to your non-EF-model type.

LINQ query to get count of records

I'm trying to retrieve some records from database along with a count, with LINQ.
DataTable dtByRecipe = (from tbrp in context.tblRecipeParents
join tbrc in context.tblRecipeChilds on tbrp.RecipeParentID equals tbrc.RecipeParentID
join tbp in context.tblProducts on tbrc.ProductID equals tbp.ProductID
join tbps in context.tblProductSales.AsEnumerable()
on tbp.ProductID equals tbps.ProductID
join tbs in context.tblSales.AsEnumerable()
on tbps.ProductSalesID equals tbs.ProductSalesID select new
{
tbrp.Recipe,
tbp.ProductID,
tbps.ProductSalesID,
tbrp.Yield,
Product = tbp.ProductCode + " - " + tbp.ProductDescription,
ProductYield = tbrp.Yield,
TotalYield = "XXX",
Cost = "YYY"
}).AsEnumerable()
.Select(item => new {
item.Recipe,
Count = GetCount(item.ProductID, item.ProductSalesID, context),
item.Yield,
Product = item.Product,
ProductYield = item.ProductYield,
TotalYield = "XXX",
Cost = "YYY"
}).OrderBy(o => o.Recipe).ToDataTable();
private int GetCount ( int ProductID, int ProductSalesID, MTBARKER_DBEntities context )
{
int query = ( from tbps in context.tblProductSales
join tbp in context.tblProducts on tbps.ProductID equals tbp.ProductID
join tbs in context.tblSales
on tbps.ProductSalesID equals tbs.ProductSalesID
where tbp.ProductID == ProductID && tbps.ProductSalesID == ProductSalesID
select tbs ).Count();
return query;
}
In above query I get the expected result but since there are around 10K records in the database it consumes a lot of time to produce the result. The issue is with the following approach I have used to get the count.
Count = GetCount(item.ProductID, item.ProductSalesID, context),
Is there any productive way that I could prevent this issue?
Well Stored Procedures is best choice for performance.Use Stored Procedures in the Entity Framework for selection and for reporting.

How can I convert this SQL Query into LINQ (OVER (PARTITION BY Date))

Here's the query I'm trying to convert into Linq:
SELECT R.Code,
R.FlightNumber,
S.[Date],
S.Station,
R.Liters,
SUM(R.Liters) OVER (PARTITION BY Year([Date]), Month([Date]), Day([Date])) AS Total_Liters
FROM S INNER JOIN
R ON S.ID = R.SID
WHERE (R.Code = 'AC')
AND FlightNumber = '124'
GROUP BY Station, Code, FlightNumber, [Date], Liter
ORDER BY R.FlightNumber, [Date]
Thanks for any help.
UPDATE: Here is the Linq code I'm trying it on; I cannot make the OVER PARTITION by Date.
var test =
(from record in ent.Records join ship in ent.Ship on record.ShipID equals ship.ID
orderby ship.Station
where ship.Date > model.StartView && ship.Date < model.EndView && ship.Station == model.Station && record.FlightNumber == model.FlightNumber
group record by new {ship.Station, record.Code, record.FlightNumber, ship.Date, record.AmountType1} into g
select new { g.Key.Station, g.Key.Code, g.Key.FlightNumber, g.Key.Date, AmmountType1Sum = g.Sum(record => record.AmountType1) });
Execute query first without aggregation:
var test =
(from record in ent.Records join ship in ent.Ship on record.ShipID equals ship.ID
orderby ship.Station
where ship.Date > model.StartView && ship.Date < model.EndView && ship.Station == model.Station && record.FlightNumber == model.FlightNumber
select new {ship.Station, record.Code, record.FlightNumber, ship.Date, record.AmountType1};
Then calculate sum
var result =
from row in test
select new {row.Station, row.Code, row.FlightNumber, row.Date, row.AmountType1,
AmountType1Sum = test.Where(r => r.Date == row.Date).Sum(r => r.AmountType1) };
This should produce the same effect as database query. Code above may contain errors, because I wrote it only here.
I've answered a similar thread on: LINQ to SQL and a running total on ordered results
On that thread it was like this:
var withRuningTotals = from i in itemList
select i.Date, i.Amount,
Runningtotal = itemList.Where( x=> x.Date == i.Date).
GroupBy(x=> x.Date).
Select(DateGroup=> DateGroup.Sum(x=> x.Amount)).Single();
In you situation, you might have to join the two tables together first while grouping, then run the same concept above on the joined table result.

Categories