Pivot in LINQ using lambda expression - linq

I am writing a lambda in linq for getting the pivoted data from the resulting list.For getting the pivoting columns am setting a where condion to get the value.the problem here is am getting default value if the where condtion fails.I dont want the column if the where condition fails.Kindly help me out.
var query = dataList
.GroupBy(c => c.IpAddress)
.Select(g => new
{
IPAddress = g.Key,
AssetType = g.ElementAtOrDefault(0).AssetTypeName,
AssetName = g.ElementAtOrDefault(0).AssetName,
//if where condition fails i dont need this column.
//also am giving c.DsName == "Active Calls" ,how to achieve tis dynamically
**ActiveCalls = g.Where(c => c.DsName == "Active Calls").Sum(c => c.CurrentValue),**
**HoldCalls = g.Where(c => c.DsName == "Hold Calls").Sum(c => c.CurrentValue),**
**CPU = g.Where(c => c.DsName == "CPU").Sum(c => c.CurrentValue),**
});

Why not just create a value to hold the sum and then specify its a type in another column. That way you don't have to deal with null columns. (The assumption is that only one type is valid at a time).
Value = g.Sum(c => c.CurrentValue), // Value as specified by the the DsName property.
DsName = c.DsName

Related

how to set value in List with out using foreach loop

I am having two lists and filter based on a group of values.
var UserIdList = response.Users.Select(p => p.Id).ToList();
var filteredRecords =
(from o in om.Organizations join u in om.Users on o.Id equals u.OrganizationId where UserIdList.Contains(u.Id)
select new { Enabled = o.Enabled, Id = u.Id }).ToList();
Now i want to set 'Exists' property in 'response.Users' to true if 'Id' exists in filteredRecords.
Please let me know how can I set value with out using foreach loop.
I have tried with
response.Users.Where(x => x.Exists = (filteredRecords .Any(z => z.Id == x.Id))).ToList();
but could not succeed as it is giving only filter results.
I want full records which are matched and which are not
Linq doesn't really support update scenarios as it's for querying data.
For lists however there's a ForEach extension method:
UserList
.ToList()
.ForEach(item=> item.Exists = filteredRecords.Any(f=> f.Id == item.Id));
Is this clearer to read and easier to understand than a foreach loop...
Edit (after question updates)
// You can't use this... it won't even compile,
// x.Exists = ... is an assignment not a condition
response.Users.Where(x => x.Exists = (filteredRecords .Any(z => z.Id == x.Id))).ToList();
What you want to do is to work with a subset of users and update the values.
response
.Users
.Where(x=> filteredRecords.Any(z => z.Id == x.Id))
.ToList() // This materialises your IEnumerable/IQueryable to allow the ForEach extension method
.ForEach(x => x.Exists = true);
you could of course use:
var usersToEnable = response.Users.Where(x=> filteredRecords.Any(z => z.Id == x.Id);
foreach(var user in usersToEnable)
user.Enabled = true;
As a direct response to:
Please let me know how can I set value with out using foreach loop. I have tried with
response.Users.Where(x => x.Exists = (filteredRecords .Any(z => z.Id == x.Id))).ToList(); but could not succeed as it is giving only
filter results. I want full records which are matched and which are
not
What you've done there is selected a collection of response user items you wish to have Exists set to true.
Now you need to set that bool in this filtered collection, and then return the full response collection afterwards, instead of returning the filtered collection.
I think this is where you're getting confused.

Getting the Error in my code when framing LINQ

My Code:
var lastName = employees
.Where(a => a.Number ==
(dm.MTM.Where(b => b.MTT.IsManager)
.Select(c => c.Number)
.FirstOrDefault()))
.Select(z => z.LastName)
.FirstOrDefault();
Error Message:
Unable to create a constant value of type 'XXX.Models.Mt.MTM'. Only primitive types or enumeration types are supported in this context.
Try:
int? num = dm.MTM.Where(b => b.MTT.IsManager).Select(c => c.Number).FirstOrDefault();
var lastName = employees.Where(a => a.Number == num).Select(z => z.LastName).FirstOrDefault();
But you should add a check
if (num == null)
{
// bad things, don't execute second query
}
between the two instructions.
The error is because in an Entity Framework query you can't do "things" too much fancy, like the things necessary to calculate num.
Try:
// Calculate the number outside of the main query
// because the result is fixed
var nb = dm.MTM
.Where(b => b.MTT.IsManager)
.Select(c => c.Number)
.FirstOrDefault();
// Perform the main query with the number parameter already calculated before
string lastName = String.Empty;
if (nb != null) // if null no need to run the query
{
lastName = employees
.Where(a => a.Number == nb)
.Select(z => z.LastName)
.FirstOrDefault();
}
You don't need to get the number from the database for each employee, calculate the value before running your main query.
This will be faster, less error-prone and better for caching.

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Find the max value in a grouped list using Linq

I have a linq expression that returns transactions in groups. Each transaction has a numerical value and I now need to know what is the highest value from all the transactions returned. This value is held in a field called TransactionId
Here is the expression I am using to get the grouped list.
var transactions = ctx.MyTransactions
.Where (x => x.AdapterId == Id)
.GroupBy(x => x.DeviceTypeId);
I now need to write an expression that works on the “transactions” grouped list to find the “max” of the TransactionId field. I’ve tried different ideas but none seem to work with the grouped results. I’m new to linq so I’m not sure how to do this.
Have you tried finding the maximum in each group and then finding the maximum of that over all groups?
int max = transactions.Max(g => g.Max(t => t.TransactionId));
Or you could just query the database again:
int max = ctx.MyTransactions
.Where(x => x.AdapterId == Id)
.Max(t => t.TransactionId);
This will give you the max in each group
var transactionIds = ctx.MyTransactions
.Where (x => x.AdapterId == Id)
.GroupBy(x => x.DeviceTypeId,
g => new {
DeviceTypeId = g.Key,
MaxTransaction = g.Max(x => x.TransactionId)
});

Linq error generic parameter or the query must use a nullable type

I got this error when i use sum function in LINQ:
The cast to value type 'Decimal' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.
GroupProduct.Where(a => a.Product.ProductID==1).Sum(Content => Content.Amount==null?0:Content.Amount),
This is what I usually use. This will cover the possibility of Amount being null and also cover the possibility of an empty set.
GroupProduct.Where(a => a.Product.ProductID == 1)
.Select(c => c.Amount ?? 0) // select only the amount field
.DefaultIfEmpty() // if selection result is empty, return the default value
.Sum(c => c)
DefaultIfEmpty() returns the default value associated with Amount's type, which is int, in which case the default value is 0.
Did you try the following:
GroupProduct.Where(a => a.Product.ProductID==1).Sum(Content => (decimal?)Content.Amount)
The code from my application looks like:
var data = query.AsEnumerable().Select(row => TaskInfo.FetchTaskInfo(row,
ctx.ObjectContext.Hours.Where(hour => hour.TaskId == row.TaskId).Sum(hour => (decimal?)hour.Duration),
ctx.ObjectContext.Notes.Count(note => note.SourceType == (int)SourceType.Task && note.SourceId == row.TaskId)));
You could exclude at source?
var sum = GroupProduct.Where(a => a.Product.ProductID==1 && a.Amount != null)
.Sum(a => (decimal)a.Amount);
Try this:
var sum = GroupProduct.Where(a => a.Product.ProductID==1).Sum(Content => (int?) Content.Amount);
sum = sum ?? 0;
This looks like it should work (and usually does) but fails when the Where() method returns null:
decimal sum1 = GroupProduct
.Where(a => a.Product.ProductID == 1)
.Sum(c => c.Amount ?? 0);
The error: "The cast to value type 'Decimal' failed because the materialized value is null" is due to the Sum() method returning null (not zero) when summing over an empty set.
Either of these work for me:
decimal? sum2 = GroupProduct
.Where(a => a.Product.ProductID == 1)
.Sum(c => c.Amount);
decimal sum3 = GroupProduct
.Where(a => a.Product.ProductID == 1)
.Sum(c => c.Amount) ?? 0;

Resources