Group by in Linq to get further details - c#

I have table data as:
Fname Lname Date ForeignKey
A B 2012-01-01 1
A B 2012-11-01 1
A B 2013-12-25 1
C K 2009-01-01 2
C K 2001-11-01 2
C K 2011-12-25 2
My table is referred as ABC in EF
So I want to group them by Foreign Key, and I am able to do that by using this query, but How to get the details of each row now?
var q = from abc in context.ABC
group abc by abc.ForeignKey into g
join efg in context.EFG on g.Key equals efg.AppId
select new
{
MortgId = g.Key,
TrackingDate = g.Max(val => val.Date),
Fname=g.?,
Lname=g.?,
Sale=efg.SalesAmount
};
foreach(var result in q)
{
if(result.Fname=="A")
{
}
}
It returns me the list.
This gives me the Record of maximum date but I want to get the details of Fname and Lname of this Maximum Date and I am not able to get any clue.
UPDATE:
The result should be like this:
Fname Lname Date ForeignKey
A B 2013-12-25 1
C K 2011-12-25 2
I want to get the details against the maximum date.
NEW UPDATE:
So I want to check on the basis of Fname and I have made a question mark that how to get the Fname of the maximum date result.
I hope it is clear now.

Get object which has max date for each group by ordering by descending, and get first:
var list = context.ABC.GroupBy(abc => abc.ForeignKey)
.Select(g => g.OrderByDescending(a => a.Date).First())
Then you can get other properties easily:
foreach (var abc in list)
{
var fname = abc.Fname;
var lname = abc.Lname;
}

Related

Complex Linq Query Update as DateTime

There are A and B tables that are related to each other. I want to create a linq query that will update the Status value in the A table if the entire row of relationship lines with the AID column in the B table is equal to or smaller than today's date in the Date field.
For example, according to the table below, the Status values of the rows with ID value 1 (AAA) and 2 (BBB) in Table A will be 1. Its Status value will not change because the line with ID value 3 (CCC) is not smaller than the current date of all the related rows in the B table.
How can I write the most stable and performance linq query?
Today : 2018-7-10
A Table
ID Name Status
1 AAA 0
2 BBB 0
3 CCC 0
B Table
ID AID Date
6 1 2018-5-3
7 2 2018-6-2
8 2 2018-6-4
9 3 2018-10-12
10 3 2018-7-7
Grouping TableB on AID
Selecting the "Max" date in each group.(Each unique AID)
Compares the selected dates with the corresponding Id in Table A.
Sets the Status value to true if the date is less or equal to the current date.
TableB.GroupBy(x => x.AId).Select(group => new { identifier = group.Key, MaxDate = group.Max(m => m.Date) }).ToList().ForEach(y =>
{
if (y.MaxDate <= DateTime.Now.Date)
{
TableA.Where(g => g.Id == y.identifier).First().Status = true;
}
});
This will select AIDs from Table B where Date is samller than now.
we select records from table A where its ID is in List from
previous step
Then we update Status value
A.Where ( a => B.Where( b => b.Date <= DateTime.Now).Select(b => b.AID).Contains(a.ID)).ForEach( a => a.Status = 1 )
/*Fetching those aS Who meet the condition. */
var aList1=(from b in dbset.Bs.Where(x=>x.Date<DateTime.Now)//TimeZone may vary
join a in dbSet.As
on b.AID equals a.ID
select a);
/*Fetching those aS Who don't meet the condition. */
var aList2=(from b in dbset.Bs.Where(x=>x.Date>=DateTime.Now)//TimeZone may vary
join a in dbSet.As
on b.AID equals a.ID
select a);
/*Removing those aS from list1 which occured in list2 */
var aFinalList=(aList1.Except(aList2)).ToList();
/*Updating status */
aFinalList.ForEach(x=>x.Status=1);
aFinalList.SaveChanges();
You can use GroupJoin extension in Lambda to Join the A and B tables then use All extension with your condition (date <= Today or any condition) then update the Status. Something like,
var lstResult = lstA.GroupJoin(lstB, a => new { a.Id }, b => new { Id = b.AId }, (a, b) => new { a, b })
.Select(x =>
{
if (x.b.All(y => y.Date <= DateTime.Now)) //Actual condition here.
{
x.a.Status = true;
return x.a;
}
else return x.a;
});
C# fiddle with sample data.

Linq to Dictionary with key and a list

My data is as under in two tables
Master Columns
ID MyDateTime
1 07 Sept
2 08 Sept
MyDatetime column in above has unique index
Detail Columns
ID Data1 Data2 Data3
1 a b c
1 x y z
1 f g h
2 a b c
I want to populate this in a dictionary. I have tried
Dictionary<DateTime, List<Detail>> result = (
from master in db.master
from details in db.detail
where (master.ID == detail.ID)
select new
{
master.MyDateTime,
details
}).Distinct().ToDictionary(key => key.MyDateTime, value => new List<Detail> { value.details });
I expect two rows in the dictionary
1, List of 3 rows as details
2, List of 1 row as details
I get an error where it complains about the key of the dictionary entered twice. The key would be the datetime which is unique in the master
This is precisely what lookups are for - so use ToLookup instead of ToDictionary:
ILookup<DateTime, Detail> result =
(from master in db.master
join details in db.detail on master.ID equals detail.ID
select new { master.MyDateTime, details })
.ToLookup(pair => pair.MyDateTime, pair => pair.details);
(You shouldn't need to use Distinct, and note the use of a join instead of a second from and a where clause.)

EF Sum between 3 tables

Say we got a Database design like this.
Customer
Id Name
1 John
2 Jack
Order
Id CustomerId
1 1
2 1
3 2
OrderLine
Id OrderId ProductId Quantity
1 1 1 10
2 1 2 20
3 2 1 30
4 3 1 10
How would I create an entity framework query to calculate the total Quantity a given Customer has ordered of a given Product?
Input => CustomerId = 1 & ProductId = 1
Output => 40
This is what I got so far, through its not complete and still missing the Sum.
var db = new ShopTestEntities();
var orders = db.Orders;
var details = db.OrderDetails;
var query = orders.GroupJoin(details,
order => order.CustomerId,
detail => detail.ProductId,
(order, orderGroup) => new
{
CustomerID = order.CustomerId,
OrderCount = orderGroup.Count()
});
I find it's easier to use the special Linq syntax as opposed to the extension method style when I'm doing joins and groupings, so I hope you don't mind if I write it in that style.
This is the first approach that comes to mind for me:
int customerId = 1;
int productId = 1;
var query = from orderLine in db.OrderLines
join order in db.Orders on orderLine.OrderId equals order.Id
where order.CustomerId == customerId && orderLine.ProductId == productId
group orderLine by new { order.CustomerId, orderLine.ProductId } into grouped
select grouped.Sum(g => g.Quantity);
// The result will be null if there are no entries for the given product/customer.
int? quantitySum = query.SingleOrDefault();
I can't check what kind of SQL this will generate at the moment, but I think it should be something pretty reasonable. I did check that it gave the right result when using Linq To Objects.

How to sum a field grouped by another in LINQ?

I am trying to find a away to SUM all the QUANTITY for a specific RECIPE (all its ingredients) into a single value to get the TOTAL QUANTITY
Assuming I have the following dataset:
RecipeName IngredientName ReceiptWeight
Food1 Ingredient1 5
Food1 Ingredient2 2
Food2 Ingredient1 12
Food2 Ingredient3 1
And I would expect to get the following:
RecipeName ReceiptWeight
Food1 7
Food2 13
The code I have so far is:
Grouping =
(
from data in dataset
group data by data.RecipeName into recipeGroup
let fullIngredientGroups = recipeGroup.GroupBy(x => x.IngredientName)
select new ViewFullRecipe()
{
RecipeName = recipeGroup.Key,
ReceiptWeight = ????
How can I get the value for RecipeWeight?
Thanks,
LINQ does have sum
from d in dataset
group d by new { d.RecipeName } into g
select new {
g.Key.RecipeName,
ReceiptWeight = g.sum(o => o.ReceiptWeight)
}

LINQ Count and Group by different Columns

id'like to count how many documents a User edited or created. Therefore I have a Datatable which contains the information sth. like this:
Input
DocumentName | ModifiedBy | CreatedBy
a Frank Frank
b Mike Frank
c John Mike
That should be the Output:
Name DocumentsModified(Total) DocumentsCreated(Total)
Frank 1 2
Mike 1 1
John 1 0
So what it did to count all documents a person edited, is the following
var query = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("ModifiedBy") into rowGroup
select new
{
Name = rowGroup.Key, ModifiedDocuments = rowGroup.Count()
};
This works fine. Now i have to count also the values of the column "Creator". Is this possible and if so, how would i do that? OK, i could iterate over the table, but it would be nice to accomplish this in the LinQ query.
I tried to use "group queryResult by new {}" but i'm not sure if i'm on the right track.
You're best bet would be to just query for created and modified separately and then combine the results with a join.
var modifiedCount = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("ModifiedBy") into rowGroup
select new
{
Name = rowGroup.Key, ModifiedDocuments = rowGroup.Count()
};
var createdCount = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("CreatedBy") into rowGroup
select new
{
Name = rowGroup.Key, CreatedDocuments = rowGroup.Count()
};
var finalResult = from first in modifiedCount
join second in createdCount
on first.Name equal second.Name
select new
{
first.Name,
first.ModifiedDocuments,
second.CreatedDocuments
};
Can't you use the same method with CreatedBy?
var query2 = from queryResult in resultTable.AsEnumerable()
group queryResult by queryResult.Field<string>("CreatedBy") into rowGroup
select new
{
Name = rowGroup.Key, ModifiedDocuments = rowGroup.Count()
};
And then use your 2 queries sorted by Name.

Categories