C# Datatable linq - where any - c#

I have a datatable that populates a list. The datatable has 3 columns, 'unit', 'clientId' and 'incident'. The incident could fx be '1. rate paid' or 'resold'.
I'm trying to exclude unit's from the list where any of it's incident is = 'resold', something like:
.Where(r => r.Field<string>("clientId") & r => r.Field<string>("unit").any() != resold))
This is my code:
var units = new List<string>();
if (showIndividualData == true)
{
units = dt.AsEnumerable()
.Where(r => r.Field<string>("clientId") == clientId)
.Select(r => r.Field<string>("unit"))
.Distinct()
.ToList();
}
else
{
units = dt.AsEnumerable()
.Where(r => r.Field<string>("clientId").Length > 0)
.Select(r => r.Field<string>("unit"))
.Distinct()
.ToList();
}

Here's a sample of a working solution. I assumed all string fields but you get the idea. I have also commented each line to explain the process of the linq for easier understanding if you have difficulties.
// some dummy table i assume you have filled
var dt = new DataTable();
// arbitrary client if, you can alter the beginning of the linq for your multi client query somehow
var clientId = "some client";
// the important linq syntax
var units = dt.Rows.Cast<DataRow>() // as datarow array
.Where(dr => dr["ClientId"].ToString() == clientId) // filter client
.GroupBy(dr => dr["unit"].ToString()) // group by unit for easy conditional after
.Where(grp => grp.ToList().All(dr => dr["incident"].ToString() != "resold")) // filter each group and keep only those where all the records are not "resold"
.Select(grp => grp.Key).ToList(); // select the key of the groups which is the "unit" column and already filtered

One can use the Any with the predicate you mentioned...just change it to
&& r.Field<string>("unit").Any(itm => !itm.Equals(resold))
and that will help discriminate it in your Where clause.

Related

LINQ efficiency

Consider the following LINQ statements:
var model = getModel();
// apptId is passed in, not the order, so get the related order id
var order = (model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId));
var orderId = 0;
var orderId = order.LastOrDefault();
// see if more than one appt is associated to the order
var apptOrders = (model.getMyData
.Where(x => x.OrderId == orderId)
.Select(y => new { y.OrderId, y.AppointmentsId }));
This code works as expected, but I could not help but think that there is a more efficient way to accomplish the goal ( one call to the db ).
Is there a way to combine the two LINQ statements above into one? For this question please assume I need to use LINQ.
You can use GroupBy method to group all orders by OrderId. After applying LastOrDefault and ToList will give you the same result which you get from above code.
Here is a sample code:
var apptOrders = model.getMyData
.Where(x => x.ApptId == apptId)
.GroupBy(s => s.OrderId)
.LastOrDefault().ToList();
Entity Framework can't translate LastOrDefault, but it can handle Contains with sub-queries, so lookup the OrderId as a query and filter the orders by that:
// apptId is passed in, not the order, so get the related order id
var orderId = model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId);
// see if more than one appt is associated to the order
var apptOrders = model.getMyData
.Where(a => orderId.Contains(a.OrderId))
.Select(a => a.ApptId);
It seems like this is all you need:
var apptOrders =
model
.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => new { y.OrderId, y.AppointmentsId });

C# Linq - Refactoring ForEach Loop with Sub List

Am trying to refactor some data in order to display some charts.
I can't seem to figure out why using the following, it lists all the values at the top rather than being sequential like the source data.
var categories = VehicleSales.Select(v => v.name).Distinct().ToList();
var refactoredResults = new List<StackedColumnChart>();
foreach (var category in categories)
{
var subresult = VehicleSales.Where(x => x.vehicleType == category)
.GroupBy(x => x.vehicleType)
.Select(gcs => new StackedColumnChart
{
Category = category,
Values = gcs.Select(x => (int)x.data).DefaultIfEmpty(0).ToList()
}).ToList();
refactoredResults.AddRange(subresult);
}
Source Data:
Then the actual results and expected results:
Thanks in advance!
You can do that without loop and selecting a distinct values, just use GroupBy method and map each group to StackedColumnChart using Select
var refactoredResults = VehicleSales
.GroupBy(s => s.Category)
.Select(g => new StackedColumnChart
{
Category = g.Key,
Values = g.Select(s => s.Value).ToList()
})
.ToList();
If the original data is not sorted and you'll need to sort the values by week number, you can use OrderBy clause before selecting a values Values = g.OrderBy(s => s.WeekNumber).Select(s => s.Value).ToList()

Get columns values in data table using linq from Entity Framework

I am new to LINQ queries, please help me out to find the solution.
I have a source in Entity Framework data model, there is a table currency bound to the source with columns currencyID and CurrencyName.
I need to get the values from the database to the DataTable using a LINQ query.
I tried something like mentioned below but it's not working:
var dataset = Source.T_Currency
.Where(x=> x.CurrencyID == x.CurrencyID && x.CurrencySymbol == x.CurrencySymbol)
.Select(x => new x.Currency
{
CurrencyID = x.CurrencyID,
CurrencySymbol = x.CurrencySymbol
}).ToList();
If you want to select all rows from T_Currency then try
Source.T_Currency
.Select(x => new
{
x.CurrencyID,
x.CurrencySymbol
})
.ToList()
To filter result by any value add Where statement before Select:
Source.T_Currency
.Where(x => x.CurrencySymbol == myCurrency) // where myCurrency is variable/parameter
.Select(x => new
{
x.CurrencyID,
x.CurrencySymbol
})
.ToList()
It is example with Select statement but actually in this case it is not requied, so Source.T_Currency.ToLost() returns the same result as the first code snippet. Difference is in type of values but if you can use original class then you should not create anonimous type.
you should use LINQ Join like this example:
var custSupJoin =
from sup in suppliers
join cust in customers on sup.Country equals cust.Country
select new { Country = sup.Country, SupplierName = sup.SupplierName, CustomerName = cust.CompanyName };

GroupBy Mongodb with Driver C#

I'm making a stadistics module and I need to do a GroupBy Operation with a Count to take the total visitors by country. I'm using MongoRepository (Link to Library)
I have this code in C# working fine, but I don't like the solution:
var repositoryIpFrom = new MongoRepository<IpFrom>();
var countries = repositoryIpFrom.Where(s => s.id == id).Select(s => s.Country).Distinct();
foreach (var country in countries)
{
statisticsCountryDto.Add(new StatisticsCountryDto()
{
Country = country,
Count = repositoryIpFrom.Count(s => s.id == id && s.Country == country)
});
}
return statisticsCountryDto;
And this one with Linq (but it's not working... the error says GroupBy is not supported)
var tst = repositoryIpFrom.Where(s=>s.id == id).GroupBy(s => s.Country).Select(n => new
{
Country = n.Key,
Count = n.Count()
});
Can I have any options to make the GroupBy and not make a lot of queries?
Thanks!!
Since you are not filtering through the query, you can resolve the query by inserting a AsEnumerable operation and then perform the grouping operations on the local data after the MongoDb driver is no longer involved.
var tst = repositoryIpFrom
.Where(s=>s.id == id)
.AsEnumerable()
.GroupBy(s => s.Country)
.Select(n => new
{
Country = n.Key,
Count = n.Count()
});

Entity framework use already selected value saved in new variable later in select sentance

I wrote some entity framework select:
var query = context.MyTable
.Select(a => new
{
count = a.OtherTable.Where(b => b.id == id).Sum(c => c.value),
total = a.OtherTable2.Where(d => d.id == id) * count ...
});
I have always select total:
var query = context.MyTable
.Select(a => new
{
count = a.OtherTable.Where(b => b.id == id).Sum(c => c.value),
total = a.OtherTable2.Where(d => d.id == id) * a.OtherTable.Where(b => b.id == id).Sum(c => c.value)
});
Is it possible to select it like in my first example, because I have already retrieved the value (and how to do that) or should I select it again?
One possible approach is to use two successive selects:
var query = context.MyTable
.Select(a => new
{
count = a.OtherTable.Where(b => b.id == id).Sum(c => c.value),
total = a.OtherTable2.Where(d => d.id == id)
})
.Select(x => new
{
count = x.count,
total = x.total * x.count
};
You would simple do
var listFromDatabase = context.MyTable;
var query1 = listFromDatabase.Select(a => // do something );
var query2 = listFromDatabase.Select(a => // do something );
Although to be fair, Select requires you to return some information, and you aren't, you're somewhere getting count & total and setting their values. If you want to do that, i would advise:
var listFromDatabase = context.MyTable.ToList();
listFromDatabase.ForEach(x =>
{
count = do_some_counting;
total = do_some_totalling;
});
Note, the ToList() function stops it from being IQueryable and transforms it to a solid list, also the List object allows the Linq ForEach.
If you're going to do complex stuff inside the Select I would always do:
context.MyTable.AsEnumerable()
Because that way you're not trying to still Query from the database.
So to recap: for the top part, my point is get all the table contents into variables, use ToList() to get actual results (do a workload). Second if trying to do it from a straight Query use AsEnumerable to allow more complex functions to be used inside the Select

Categories

Resources