Building a list in a dictionary (LINQ to SQL) - c#

I am try to build a dictionary with a list of dates as values.
I am not sure what extension method that I need to use inorder to get to the solution. Tried doing a ToList() on the value field but its throwing an exception.
Below is the code that I am using.
GolfitoDataContext db = new GolfitoDataContext();
var dic = db.GetTable<History>()
.Select(p => new { p.Title, p.Date})
.Where(x => x.Date >= startDateFilter && x.Date <= endDateFilter)
.DistinctBy(x => x.Title)
.AsEnumerable()
.ToDictionary(k => k.Title, k => k.Date);
For example for the below data
Date Title
2013-07-18 22:51:45.000 QA
2013-07-18 22:52:30.000 Controller
2013-07-18 22:52:30.000 Controller
2013-07-18 22:58:00.000 Agent
2013-07-18 23:07:00.000 QA
2013-07-18 23:07:45.000 Controller
2013-07-18 23:08:30.000 Planning
I am trying to build a dictionary which will give me all the instances of individual titles(QA,Controller,etc.) and their occurrences (date on which the instances occurred). Basically building a Dictionary<string,List<DateTime>>

You should use GroupBy:
var dic = db.GetTable<History>()
.Select(p => new { p.Title, p.Date})
.Where(x => x.Date >= startDateFilter && x.Date <= endDateFilter)
.GroupBy(x => x.Title)
.ToDictionary(g => g.Key, g => g.Select(x => x.Date).ToList());

The ToLookup method encompasses that:
GolfitoDataContext db = new GolfitoDataContext();
var dic = db.GetTable<History>()
.Select(p => new { p.Title, p.Date})
.Where(x => x.Date >= startDateFilter && x.Date <= endDateFilter)
.ToLookup(k => k.Title, k => k.Date);
A lookup is basically the same as a multi-map, and can be used for example as:
foreach(var date in dic[title])
{
// ...
}

you need to build the list before you try to build the dictionary. You can do this by use of group by
var dic = (from x in db.GetTable<History>()
where x.Date >= startDateFilter && x.Date <= endDateFilter
group x.Date by x.Title)
.ToDictionary(grp => grp.Key, grp.ToList());

Related

How to iterate over a list to build a Linq query

I have the following working query:
posts.Where(post =>
post.Fields
.Where(x =>
x.RegionId == "RecipeArticleDetails" &&
(x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime")
)
.GroupBy(x => x.PostId)
.Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) })
.Where(x => x.Value > 10 && x.Value < 40)
.Any()
)
List<string> suppliedTimes = new List<string>(){
"10-60","0-10"
};
I would like to replace Where(x => x.Value > 10 && x.Value < 40) so it looks up from a list of ranges:
List<string> suppliedTimes = new List<string>(){
"10-60","0-10"
};
My understanding is I can use select to iterate over the items:
posts.Where(post =>
suppliedTimes.Select(x => new {low = Convert.ToInt32(x.Split("-",StringSplitOptions.RemoveEmptyEntries)[0]), high = Convert.ToInt32(x.Split("-",StringSplitOptions.RemoveEmptyEntries)[1]) })
.Any( a =>
post.Fields
.Where(x =>
x.RegionId == "RecipeArticleDetails" &&
(x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime")
)
.GroupBy(x => x.PostId)
.Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) })
.Where(x => x.Value > a.low && x.Value < a.high)
.Any()
)
)
However this code results in the error:
could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Please can someone explain how I can achieve this and why what I have isn't working.
To make it work with EF Core I would suggest my extnsion FilterByItems and change the way how to retrieve records.
List<string> suppliedTimes = new List<string>(){
"10-60","0-10"
};
var ranges = suppliedTimes
.Select(x => x.Split("-", StringSplitOptions.RemoveEmptyEntries))
.Select(x => new {
low = Convert.ToInt32(x[0]),
high = Convert.ToInt32(x[1])
});
var fields = context.Fields
.Where(x =>
x.RegionId == "RecipeArticleDetails" &&
(x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime")
)
.GroupBy(x => x.PostId)
.Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) })
.FilterByItems(ranges, (e, r) => e.Value > r.low && e.Value < r.high, true);
var posts = posts
.Join(fields, p => p.Id, f => f.ID, (p, f) => p);

How to select last hour and groupby minute?

I want to select data from SQL database using EF, select the last hour and then group by minute.
var result = _dbContext.views
.Where(x => x.Id == id && x.Created > DateTime.UtcNow.AddHours(-1))
.OrderBy(x => x.Created)
.GroupBy(x=> x.Created.Where({Range is 1 minute}));
DateTime instance has a Minute property which is an int so you can use the x.Created.Minute for grouping:
var result = _dbContext.views
.Where(x => x.Id == id && x.Created > DateTime.UtcNow.AddHours(-1))
.OrderBy(x => x.Created)
.GroupBy(x=> x.Created.Minute}));

c# lambda reading each row with GROUP BY and SUM

This is the working query i was using in my management studio.
SELECT TOP 5 productCode, SUM(productSales) AS sales
FROM sellingLog
WHERE (salesYear = '2014')
GROUP BY productCode
ORDER BY sales DESC
I want to convert the query above into lambda, but i can't seems to make it works. the lambda still lacks of order by and select the productCode
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(b => b.Sum(u => u.productSales)).Take(5)
.ToList();
foreach(var v in topProduct)
{
//reading 'productCode' and 'sales' from each row
}
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(g => new { productCode = g.Key, sales = g.Sum(u => u.productSales) })
.OrderByDescending(x => x.productCode)
.Take(5)
.ToList();
You can use the .Key with group by to get productCode
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(b => new {u.Key, b.Sum(u => u.productSales)}).Take(5)
.OrderByDescending(b=>b.Sales)
.ToList();

Exception while building a dictionary (Linq to SQL)

Well I am trying to build a dictionary using linq to SQL. Not sure how to pick distinct values using the below query. The idea to is fetch the instances of a title between a date.
GolfitoDataContext db = new GolfitoDataContext();
var dic = db.GetTable<History>()
.Select(p => new { p.Title, p.Date }).Where(x => x.Date >= startDateFilter && x.Date <= endDateFilter)
.AsEnumerable()
.ToDictionary(k => k.Title, v => v.Date);
I get an exception that "An item with the same key has already been added."
I know its got to do with the "title" being repeated. But not sure how to apply the Distinct() method in the above condition to be able to build the dictionary. If I am doing something wrong, please correct me. Thanks!
This should work:
GolfitoDataContext db = new GolfitoDataContext();
var dic = db.GetTable<History>()
.Select(p => new { p.Title, p.Date }).Where(x => x.Date >= startDateFilter && x.Date <= endDateFilter)
.DistinctBy(p => p.Title)
.AsEnumerable()
.ToDictionary(k => k.Title, v => v.Date);
You can do this by using MoreLinQ
var dic = db.GetTable<History>()
.Select(p => new { p.Title, p.Date }).Where(x => x.Date >= startDateFilter && x.Date <= endDateFilter)
.DistinctBy(x=>x.Title)
.AsEnumerable()
.ToDictionary(k => k.Title, v => v.Date);

How can I check if the integer value of a string is less than something in LINQ?

I have the following:
var topRole = 25;
var menuItems = _contentRepository.GetPk()
.Where(m => m.Status <= topRole)
.OrderBy(m => m.Order)
.Select(m => new MenuItem
Status has values of "00", "05" or "10"
Is there some way I can convert m.Status to an integer and then compare to see if it is less than or equal to topRole?
var menuItems = _contentRepository.GetPk()
.Where(m => int.Parse(m.Status) <= topRole)
.OrderBy(m => m.Order)
.Select(m => new MenuItem);
If this query is for LINQ to SQL, you may need to use Convert.ToInt32 instead:
var menuItems = _contentRepository.GetPk()
.Where(m => Convert.ToInt32(m.Status) <= topRole)
.OrderBy(m => m.Order)
.Select(m => new MenuItem);
use int.Parse(m.Status)
var menuItems = _contentRepository.GetPk()
.Where(m => int.Parse(m.Status) <= topRole)
.OrderBy(m => m.Order)
.Select(m => new MenuItem)
EDIT: changed "parse" to "Parse".

Categories