C# SELECT GROUP by SUM LINQ - c#

I have some tables which i am joining with LINQ, this is one of the first times using it so im not that familiar with it.
The next query is as:
var query = from catalogoV in catalogo_DT.AsEnumerable()
where catalogoV.Field<String>("Incluye GPS") == "yes"
join vehicle in vehicleData.AsEnumerable()
on catalogoV.Field<String>("Numero Economico") equals vehicle.Field<String>("DisplayName")
join actividad in activityData.AsEnumerable()
on vehicle.Field<Guid>("VehicleId") equals actividad.Field<Guid>("VehicleId")
select new {Displayname = catalogoV.Field<String>("Numero Economico"), ID = vehicle.Field<Guid>("VehicleId"), Increment = actividad.Field<Single>("IncrementalDistance") };
This is an example of the results i get
{ Displayname = "0DNP-625", ID = {651e5858-bc54-4459-a5de-31144eed3374}, Increment = 0.1 }
{ Displayname = "0DNP-625", ID = {651e5858-bc54-4459-a5de-31144eed3374}, Increment = 0.4 }
{ Displayname = "0DNP-625", ID = {651e5858-bc54-4459-a5de-31144eed3374}, Increment = 4.5 }
{ Displayname = "0003-333", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 0.5 }
{ Displayname = "0003-333", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 5.2 }
But i really want to get the sum of increment back and not all the rows for it.
such as:
{ Displayname = "0003-333", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 5.7 }
{ Displayname = "0DNP-625", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 5.0 }
From what i have read i need to place a gorup in my statement but i dont know how i should mix it with my select, and i cant find something like this on the reference MSDN

You probably need to use a group join, rather than just join, for the actividad field. Here's how:
var query =
from catalogoV in catalogo_DT.AsEnumerable()
where catalogoV.Field<String>("Incluye GPS") == "yes"
join vehicle in vehicleData.AsEnumerable()
on catalogoV.Field<String>("Numero Economico") equals vehicle.Field<String>("DisplayName")
join actividad in activityData.AsEnumerable()
on vehicle.Field<Guid>("VehicleId") equals actividad.Field<Guid>("VehicleId")
into actividads
let ID = vehicle.Field<Guid>("VehicleId")
orderby ID
select new
{
Displayname = catalogoV.Field<String>("Numero Economico"),
ID,
Increment = actividads.Sum(x => x.Field<Single>("IncrementalDistance"))
};
I've added ordering as per your comment.

Related

Linq Query Join to Subquery with In clause

I have a query from an old application that I am attempting to convert to an Entity Framework Core application. The relationship I am working with is a simple one to many, where one Order can have many OrderEvents. The old query looks something like this:
select Order.Id, mostRecent.*
from Order
left join OrderEvent mostRecent
on mostRecent.Id in (select top(1) Id
from OrderEvent
where OrderEvent.OrdId = Order.Id
and OrderEvent.PostDateTime is not null
order by OrderEvent.PostDateTime desc)
where Order.SomeColumn = 'some value'
I am struggling with figuring out how to write this query in LINQ. It doesnt seem that one can use anything other than equals when doing using join, so I first attempted something like:
var test = (from order in _context.Ord.AsNoTracking()
join mostRecentQuery in _context.OrdEvt.AsNoTracking()
on (from orderEvent in _context.OrdEvt.AsNoTracking()
where orderEvent.PostDateTime != null && orderEvent.OrdId == order.Id
orderby orderEvent.PostDateTime descending
select orderEvent.Id).FirstOrDefault()
equals mostRecentQuery.Id
into mostRecentResults
from mostRecent in mostRecentResults.DefaultIfEmpty()
select new
{
OrderId = order.Id,
OrderEvent = mostRecent
}).ToList();
Whatever sql this spit out, it appears to be so slow that I cant even run it connected to Sql Server. I am however able to run this query when using Sqlite and it generates the following sql:
SELECT 'big list of fields....'
FROM "Ord" AS "order"
LEFT JOIN "OrdEvt" AS "mostRecentQuery" ON COALESCE((
SELECT "orderEvent0"."Id"
FROM "OrdEvt" AS "orderEvent0"
WHERE "orderEvent0"."PostDateTime" IS NOT NULL AND ("orderEvent0"."OrdId" = "order"."Id")
ORDER BY "orderEvent0"."PostDateTime" DESC
LIMIT 1
), X'00000000000000000000000000000000') = "mostRecentQuery"."Id"
This is close do what I am going for, but Im not sure why the COALESCE function is being used.
Is it possible to represent the query I am trying to convert, in Linq query syntax?
I'm not sure what your problem is, because you left out why it doesn't compile.
Bute here and simple example whith a join and choosing one event for an order:
public class Order
{
public int OrderId { get; set; }
public string OrderName { get; set; }
}
public class OrderEvent
{
public int OrderId { get; set; }
public string EventName { get; set; }
public DateTime Date { get; set; }
}
public static void Main(string[] args) // Here our Exe-Args are delivered to our program..
{
List<Order> orders = new List<Order>()
{
new Order() { OrderId = 1, OrderName = "One" }
};
List<OrderEvent> orderEvents = new List<OrderEvent>()
{
new OrderEvent() { OrderId = 1, EventName = "EventTwo", Date = DateTime.Now.AddHours(-1) },
new OrderEvent() { OrderId = 1, EventName = "EventOne", Date = DateTime.Now },
new OrderEvent() { OrderId = 1, EventName = "EventThree", Date = DateTime.Now.AddHours(-2) },
new OrderEvent() { OrderId = 2, EventName = "EventX", Date = DateTime.Now },
};
var tmp = orders.GroupJoin( // Join something to our orders
orderEvents, // join all events
o => o.OrderId, // key of our order
e => e.OrderId, // foreign-key to order in our event
(o, es) => // lambda-expression "selector". One order "o" and multiple events "es"
es.OrderByDescending(e => e.Date) // We order our events
.Select(s => new // we build a new object
{
OrderId = o.OrderId,
OrderName = o.OrderName,
RecentEvent = s.EventName
}).First()); // we choose the object with biggest date (first after orderDesc)
foreach (var item in tmp)
{
Console.WriteLine(item.OrderId + ", " + item.OrderName + ", " + item.RecentEvent);
}
tmp = from o in orders
join e in orderEvents on o.OrderId equals e.OrderId into es
select new
{
OrderId = o.OrderId,
OrderName = o.OrderName,
RecentEvent = (from x in es orderby x.Date descending select x.EventName).First()
};
foreach (var item in tmp)
{
Console.WriteLine(item.OrderId + ", " + item.OrderName + ", " + item.RecentEvent);
}
}

Calculating product's quantity with nested EF Query

I want to calculate the quantity of every product. I want to use these tables for this.
I want take result like this.
StockId | StockName | Sum(ProductNumber) [actually product quantity]
I tried this code for can take right result but It is returning null value even though it is the condition that satisfies the conditions.
CimriContext context = new CimriContext();
public ICollection<StockDto.StockHeader> FillDataGrid(int userCompanyId)
{
ICollection<StockDto.StockHeader> Stocks = context.Stocks.Where(c => c.UserCompanyId==userCompanyId).
Select(c => new StockDto.StockHeader()
{
StockId = c.StockId,
StockName = c.StockName,
Piece=0
}).ToList();
ICollection<StockDto.StockHeader> ProductHeader = new List<StockDto.StockHeader>();
foreach (var products in Stocks)
{
products.Piece = context.ProductTransactions.Where(p => p.StockId==products.StockId).Sum(s => s.ProductNumber);
ProductHeader.Add(products);
}
return ProductHeader.ToList();
}
You want to retrieve ProductCount for per stock record. You can perform it by joining two tables and grouping StockId and StockNumber like this;
var query = from stocks in context.Stocks
join products in context.ProductTransactions ON stocks.StockId equals products.StockId
where stocks.UserCompanyId = userCompanyId
group stocks by new
{
stocks.StockId,
stocks.StockName
} into gcs
select new
{
StockId = gcs.Key.StockId,
StockName = gcs.Key.StockName,
ProductCounts = gcs.Count()
};

Using LINQ to get information from two tables, with a join

I have a linq statement to populate two labels. The thing is, this information comes from two tables. I Have a join to join the two tables, except i cant get my Terms and Conditions from my Campaign table. Its only picking up the RedemptionLog table columns. Anyone to help with this?
MSCDatabaseDataContext MSCDB = new MSCDatabaseDataContext();
var q = from row in MSCDB.Tbl_RedemptionLogs
join d in MSCDB.Tbl_Campaigns on row.CampaignId equals d.CampaignId
orderby row.VoucherCode descending
select row;
var SeshVoucherDisplay = q.First();
lblCode.Text = SeshVoucherDisplay.VoucherCode;
lblTerms.Text = SeshVoucherDisplay
For the SeshVoucherDisplay variable, it only picks up from the RedemptionLogs table, yet i did a join? Any help?
Try something like this :
var SupJoin = from row in MSCDB.Tbl_RedemptionLogs
join d in MSCDB.Tbl_Campaigns on row.CampaignId equals d.CampaignId
orderby row.VoucherCode descending
select new { Id = row.ID, SupplierName = row.SupplierName,
CustomerName = d.CompanyName };
The column names are just for example purpose. Put your own there. And thereafter, you can apply First on it and use that particular variable.
Hope this helps.
Well, by writing select row you asked LINQ to give back to you only row.
If you want both elements, you need to ask for both of them, e.g. by writing select new { row, d }.
In this example
var foo =
new []
{
new { Id = 1, Name = "a" },
new { Id = 2, Name = "b" },
new { Id = 3, Name = "c" }
};
var bar =
new []
{
new { Id = 1, Name = "d" },
new { Id = 2, Name = "e" },
new { Id = 3, Name = "f" }
};
var baz =
from a in foo
join b in bar on a.Id equals b.Id
select new { a, b };
var qux =
from a in foo
join b in bar on a.Id equals b.Id
select new { a, b };
In baz you'll find only a list of foos, in qux you'll find a list of both foos and their bar.
Try this:
var query = (from row in MSCDB.Tbl_RedemptionLogs
join d in MSCDB.Tbl_Campaigns on row.CampaignId equals d.CampaignId)
orderby row.VoucherCode descending
select new
{
columnname = row.columnname
});
When writing select row you relate to the row you defined in from row in MSCDB.Tbl_RedemptionLogs.
However if you want the data from both tables you have to write something similar to this:
select new {
// the properties of row
Redemption = row.redemption,
// the properties of d
Campaign = d.CampaignID // alternativly use may also use row.CampaignID, but I wanted to show you may acces all the members from d also
}

SQL to Linq select multiple columns in group by

I would like to convert a SQL statement to LINQ but i have some problems doing it.
The sql statement is :
SELECT
C.[Call_Date], CC.[Company], R.Resolution,
COUNT_BIG(*) AS CNT,
SUM([Duration]) AS Total
FROM
[Calls] C
Join
[CompanyCharges] CC on [Company_Charge] = [CompanyCharge]
Join
[Resolutions] R on C.Call_Resolution = R.Resolution
where
Call_Date >= '05/29/2013'
Group By
C.[Call_Date], CC.[Company], CC.[CompanyCharge], R.Resolution, R.Resolution_Order
I wrote something like :
var stats = from c in dbContext.Calls
join cc in dbContext.CompanyCharges on c.Company_Charge equals cc.CompanyCharge
join r in dbContext.Resolutions on c.Call_Resolution equals r.Resolution
where (c.Call_Date > "05/29/2013")
group new { c, cc, r } by new { c.Call_Date, cc.CompanyCharge, r.Resolution, r.Resolution_Order } into statsGroup
select new { Count = statsGroup.Count(), ??? };
I managed to count the elements, but i need a sum[duration] and some columns from different tables.
Please share your wisdome with me.
Assuming that the [Duration] field is part of the [Calls] table:
var stats = /* ... */
select new
{
Count = statsGroup.Count(),
Total = statsGroup.Sum(stat => stat.c.Duration),
};
You'd probably want to include your grouping fields in the new anonymous type as well:
var stats = /* ... */
select new
{
Call_Date = statsGroup.Key.c.Call_Date,
CompanyCharge = statsGroup.Key.cc.CompanyCharge,
Resolution = statsGroup.Key.r.Resolution,
Count = statsGroup.Count(),
Total = statsGroup.Sum(stat => stat.c.Duration),
};

Counting records in C# using LINQ

I have a simple SQL query:
Select ID, COUNT(ID) as Selections, OptionName, SUM(Units) as Units
FROM tbl_Results
GROUP BY ID, OptionName
The results I got were:
'1' '4' 'Approved' '40'
'2' '1' 'Rejected' '19'
'3' '2' 'Not Decided' '12'
I have to encrypt the data in the database, and as such am unable to sum the data in relational form. To get around this I decrypt the data in the application layer, and want to use LINQ to query it there. I need the following results:
'1' 'Approved' '10'
'3' 'Not Deceided' '6'
'2' 'Rejected' '19'
'1' 'Approved' '15'
'1' 'Approved' '5'
'3' 'Not Deceided' '6'
'1' 'Approved' '10'
I put these results into class and create a strongly typed list:
public class results
{
public int ID {get;set;}
public string OptionName {get;set;}
public int Unit {get;set;}
}
I almost have the LINQ query to bring back the results like the SQL query about:
var q = from r in Results
group p.Unit by p.ID
int g
select new {ID = g.Key,
Selections = g.Count(),
Units = g.Sum()};
How do I ensure my LINQ query also give me the Option Name?
If I created a class called Statistics to hold my results how would I modify the LINQ query to give me List<Statistics> result set?
public class results
{
public int ID {get;set;}
public int NumberOfSelections { get; set; }
public string OptionName {get;set;}
public int UnitTotal {get;set;}
}
You're currently just grouping by the ID. Instead, as per the original query, you need to group by the option name too. That way each group's key will contain both the ID and the option name. Here's just that change:
var q = from r in Results
group r.Unit by new { p.ID, p.OptionName } into g
select new { ID = g.Key.ID,
OptionName = g.Key.OptionName
Selections = g.Count(),
UnitTotal = g.Sum() };
Now, it wasn't immediately obvious to me that you were selecting just the "unit" part for the group item. I missed "group p.Unit by" in the query expression. My bad... but others may do likewise. Here's an alternative, which makes the group contain the items, and then sums the units in the projection:
var q = from r in Results
group r by new { p.ID, p.OptionName } into g
select new { ID = g.Key.ID,
OptionName = g.Key.OptionName
Selections = g.Count(),
UnitTotal = g.Sum(x => x.Unit) };
This query groups by id and option name thus making it available:
var q = from r in Results
group p.Unit by new { ID = p.ID, OptionName = p.OptionName } into g
select new {
ID = g.Key.ID,
OptionName = g.Key.OptionName,
Selections = g.Count(),
Units = g.Sum()
};
To return your custom result class use:
var q = from r in Results
group p.Unit by new { ID = p.ID, OptionName = p.OptionName } into g
select new results() {
ID = g.Key.ID,
OptionName = g.Key.OptionName,
NumberOfSelections = g.Count(),
UnitTotal = g.Sum()
};

Categories