Linq query problem - c#

I have a linq query which presents data that is present in CustomersRecord Table as follows. Now I'm grouping the data on invoice number and date of transaction and presenting the data in descending order sorted on Date of Transaction. This is the following query I'm using to achieve that.
(from result in db.CustomersRecords
orderby result.Date_Of_Transaction.Value descending
group result
by new { result.Invoice_Number, result.Date_Of_Transaction } into intermediateResult
select new { InvoiceNumber = intermediateResult.Key.Invoice_Number, DateOfTransaction = intermediateResult.Key.Date_Of_Transaction, TotalAmount = intermediateResult.Sum(result => result.Total_Amount) }).ToList();
But mysteriously I'm getting the data in ascending order, the screen shot is shown here
I don't understand what is happening inside.

Move the order by to after you do your group by
(from result in db.CustomersRecords
group result
by new { result.Invoice_Number, result.Date_Of_Transaction } into intermediateResult
orderby intermediateResult.Key.Date_Of_Transaction descending
select new { InvoiceNumber = intermediateResult.Key.Invoice_Number, DateOfTransaction = intermediateResult.Key.Date_Of_Transaction, TotalAmount = intermediateResult.Sum(result => result.Total_Amount) }).ToList();
The reason why this is so, is because the group by result.Invoice_Number is overriding the previous order by. Since Invoice numbers are usually given in Date order it appears to be in Date Ascending.

Related

Selecting top two of the combined group by linq

I am trying to figure out how to pick the last two "Transactions" from my query.
My Query looks like this
var summary= (from tType in _context.CommandCentre.TransactionTypes
join tSummary in _context.CommandCentre.TransSummary on tType.Id equals tSummary.TransactionType
where tSummary.ChargeFlag.ToLower() == ChargeFlag.Overcharge.ToString().ToLower()
group tSummary by new { tType.Name, tSummary.NumberOfTransactions, tSummary.PeriodDate }
into gResult
select new
{
Fee = gResult.Key.Name,
TransactionCount = gResult.Key.NumberOfTransactions,
Period = gResult.Key.PeriodDate,
ActualAmount = gResult.Sum(x => x.ActualAmount),
}).OrderByDescending(x=>x.Period);
Now if I do a Take(2) I get only the last two records, while I want to get the last two records for every "Fee" of my selection. Basically Two records for every "Fee" ordered by "Period" date.
not sure how to do this in a single query.
Try this :
var result = summary.GroupBy(p => p.Fee)
.SelectMany(d => d.OrderBy(r => r.Period).Take(2))
.ToList();

Linq How to get the master record and a specific field of inner details record

Given a DB structure of this type:
Auction =0..N=> Bidders =0..N=> Bids
where each entity has several fields (e.g. auction title, bidder.name, bid.date, bid.amount, etc.).
and given the auction id, I would like to run a LINQ query that extracts in one shot:
all fields of the auction (via its given id),
the id and the name of the best bidder (ignoring other bidder's fields)
the id and the amount of the best bid of the best bidder (ignoring other bid's fields)
{
AuctionId,
AuctionTitle,
AuctionStartDate,
...,
IdOfTheBestBidder,
NameOfTheBestBidder,
IdOfTheBestBid,
AmountOfTheBestBid
}
All this in one shot and most efficient way. I.e. without loading all bidders and/or all bids for successive processing.
var qry = from auction in db.Auctions
from bidder in auction.Bidders
...;
Assuming the "best bid" is the bid with highest amount, you can build a LINQ to Entities query which orders the bids by amount in descending order and takes the first (with all related data), then project just the needed fields. It will be translated and executed as single SQL query (no auction, bidder or bid object will be loaded in the client memory).
For single auction, it would be something like this:
var result = (
from auction in db.Auctions
where auction.Id == auctionId
from bidder in auction.Bidders
from bid in bidder.Bids
orderby bid.Amount descending
select new
{
AuctionId = auction.Id,
AuctionTitle = auction.Title,
AuctionStartDate = auction.StartDate,
...,
IdOfTheBestBidder = bidder.Id,
NameOfTheBestBidder = bidder.Name,
IdOfTheBestBid = bid.Id,
AmountOfTheBestBid = bid.Amount,
}).FirstOrDefault();
For all auctions it would be similar, but with subquery per each auction:
var result = (
from auction in db.Auctions
from best in (from bidder in auction.Bidders
from bid in bidder.Bids
orderby bid.Amount descending
select new { bidder, bid }).Take(1)
select new
{
AuctionId = auction.Id,
AuctionTitle = auction.Title,
AuctionStartDate = auction.StartDate,
...,
IdOfTheBestBidder = best.bidder.Id,
NameOfTheBestBidder = best.bidder.Name,
IdOfTheBestBid = best.bid.Id,
AmountOfTheBestBid = best.bid.Amount,
}).ToList();
You can use two linq querys, first one to find the best bid as follows,
var biddersList= ( from bidder in db.Bidders
join bid in db.Bids
on bidder.Id equals bid.bidderId
where //Here you can give the conditions to select best bid of a bidder
group new { bidder, bid } by new { bidder.AuctionId } into bidandbidder
from grp in bidandbidder.DefaultIfEmpty()
select new {
grp.bidder.AuctionId,
grp.bidder.Id,
grp.bidder.Name,
grp.bid.Id,
grp.bid.Amount
}
);
In Second linq query use biddersList as follows to find the auction details with the best bid of the best bidder by the given given_auction_Id.
var auctionList = ( from ac in db.Auction
join bd in biddersList
on ac.Id equals bd.AuctionId
where ac.Id == given_auction_Id and //here you can give the conditions to select best bidder
select new{
// select fields
}
);

Group By with multiple column

I have data in a table as below
RowId | User | Date
--------------------------
1 A 2015-11-11 08:50:48.243
2 A 2015-11-11 08:51:01.433
3 B 2015-11-11 08:51:05.210
Trying to get the data as below:
User, Date, Count
A 2015-11-11 2
B 2015-11-11 1
Select User,Date,Count(User) from Table1
Group By User,Date
It is returning me 3 rows because of time involved in Date field.
How to get this in SQL and Linq.
Please suggest me.
EDITING:
I am able to get it in SQL
Select User,Cast(Date as Date),Count(User) from Table1
Group By User,Cast(Date as Date)
EDITING:
adding linq query
var details = db.table1.GroupBy( r => new { r.RowId,r.User,r.Date})
.Select(g => new {Name = g.Key, Count = g.Count()}).ToList();
For Linq Query just do the following: (you need to import using System.Data.Entity.SqlServer namespace.
Execute this linq query all calculations are done on the server database. Notice that Table1s represents the DbSet for Table1 and context is your DbContext instance.
var query = from item in context.Table1s
group item by new
{
item.User,
Year = SqlFunctions.DatePart("yyyy", item.Date),
Month = SqlFunctions.DatePart("mm", item.Date),
Day = SqlFunctions.DatePart("dd", item.Date)
} into g
select new { g.Key.User, g.Key.Year, g.Key.Month, g.Key.Day, Count = g.Count() };
Then create the final result like this:
var result = query.ToList().Select(p =>
new
{
p.User,
Date = new DateTime(p.Year.Value, p.Month.Value, p.Day.Value),
p.Count
}).ToList();
Other solution is to create a SQL View that will be used by DbContext to retrive the data you want. The SQL View body must be the SQL your wrote in your question.
EDIT 2 : DbFunctions
Like Cetin Basoz pointed in comments we can use System.Data.Entity.DbFunctions as well. And the code is more cleaner than using SqlFunctions. This will work only with EF 6 and greater. The version using SqlFunctions work with EF 4 and greater.
var query = from item in context.Table1s
group item by new
{
item.User,
Date = DbFunctions.TruncateTime(item.Date)
} into g
select new { g.Key.User, g.Key.Date, Count = g.Count() };
EDIT 1 : this is specific for Cetin Basoz's answer :
As we all know using AsEnumerable is not efficient for doing what is needed.
The second solution he gives us which is :
var grouped = from d in db.MyTable
group d by new {
User = d.User,
Date=d.Date.HasValue ? d.Date.Value.Date : (DateTime?)null} into g
select new {User=g.Key.User, Date=g.Key.Date, Count=g.Count()};
This solution just not work because of this :
The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
If the time is the problem, you can first convert it:
select User, CAST(dateColumn AS DATE) as dateConverted
into #tempTable
from myTable
then using a window function or a group by:
select *,
count(user) over (partition by date) as userCount
from #tempTable
This should work in SQL server, don't know about Linq
edit: If the date part is the problem, just select into from your table to a table with the casted date. Then you won't have this problem in Linq.
var grouped = from d in db.MyTable.AsEnumerable()
group d by new {
User = d.User,
Date=d.Date.HasValue ? d.Date.Value.Date : (DateTime?)null} into g
select new {User=g.Key.User, Date=g.Key.Date, Count=g.Count()};
Sooner or later, someone would say that this is not server side grouping and would suffer from performance and they would be right. Without Enumerable it is serverside but at the cost of another call per group, so here is another way:
public class MyResult
{
public string User {get;set;}
public DateTime? Date {get;set;}
public int Count {get;set;}
}
var grouped = db.ExecuteQuery<MyResult>(#"select [User],
Cast([Date] as Date) as [Date],
Count(*) as [Count]
from myTable
group by [user], Cast([Date] as Date)");
EDIT: I don't know why I thought the other way before, this would just work serverside and do it, AsEnumerable() was not needed:
var grouped = from d in db.MyTable
group d by new {
User = d.User,
Date=d.Date.HasValue ? d.Date.Value.Date : (DateTime?)null} into g
select new {User=g.Key.User, Date=g.Key.Date, Count=g.Count()};

How do I get the most recent entry from a table using LINQ?

I have a table of prices, which has a column for Date Updated. Every time there is a price change, a new entry is made to the table.
In order to return the most up to date price, I am trying to order by date, and then use .Last() to get the newest entry:
var upgrades = from d in vf.tl_phn_devices
where d.available == true
select new
{
DeviceName = d.tl_phn_manufacturer.manufacturer + " " + d.model,
Price = (from p in vf.tl_phn_prices
where p.deviceID == d.deviceID
orderby p.dateUpdated ascending
select p.price).Last(),
URL = d.url,
ImageURL = d.image
};
However, when I run the above I get an error saying that .Last() is unsupported.
I have also tried .AsEnumberable().Last() but this didn't work either.
Elsewhere in the code I got round a similar issue by taking an extra step:
var orders = (from o in vf.tl_phn_orders
where o.login == CurrentUserName
orderby o.date ascending
select new
{
Login = o.login,
Name = o.name,
Device = o.tl_phn_device.tl_phn_manufacturer.manufacturer + " " + o.tl_phn_device.model,
Price = o.tl_phn_price.price,
date = o.date
}).AsEnumerable();
var order = orders.LastOrDefault();
But I want to do it all in one "hit" so I can return it in the first query.
Just do orderby descending and then Select First.
Last and LastOrDefault are not supported with Entity framework, since they can't get translated into underlying language (SQL for your case)
orderby p.dateUpdated descending
select p.price).First(),
You may also see: Supported and Unsupported LINQ Methods (LINQ to Entities)
Use First() and change the order:
var upgrades = from d in vf.tl_phn_devices
where d.available
select new
{
DeviceName = d.tl_phn_manufacturer.manufacturer + " " + d.model,
Price = (from p in vf.tl_phn_prices
where p.deviceID == d.deviceID
orderby p.dateUpdated descending
select p.price).First(),
URL = d.url,
ImageURL = d.image
};
The problem is that EntityFramework cannot generate the SQL for your query.
Your second query's use of .Last() works because you have loaded the entities into memory (with .AsEnumerable()) and are now using LINQ to Objects instead of LINQ to Entities.
You cannot do the same with the first query because of the nested queries.

LINQ: adding OrderBy to query

I'm at the finish line for my university project, and I'm kinda stuck at finishing a query.
The working query looks like this:
var Report = from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
};
I would really appreciate it if you can show me, how to Order the results by the given "Quantity" in descending order.
Thanks!
var Report = (from query in Document.Descendants("order")
group query by query.Element("seller").Value into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
})
.OrderByDescending(order => order.Quantity);
Please do this :
var Report = (from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
}).OrderByDescending(x => x.Quantity);
HTH !!!!
(Kudos to LINQ Orderby Descending Query )
The answers by Skippy and Andrei work, but you can also write as
var Report = from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
let qty = qGroup.Sum(p =>int.Parse(p.Element("quantity").Value)).ToString()
orderby qty descending
select new Orders
{
Seller = qGroup.Key,
Quantity = qty
};
if you'd rather keep it all in one syntax.

Categories

Resources