Linq ToDictionary Not Defined? - linq

I have this code
var contacts = dr.mktDoctorContacts
.GroupBy(x => x.ContactType)
.Select(zb => new
{
Key = zb.Key,
GroupWiseContacts = zb.Select(x => x.Contact).ToList()
})
.ToDictionary<string,List<string>>(y => y.Key, y => y.GroupWiseContacts)
I don't know what is wrong with this code.
Compile time error msg says:System.Generic.IEnumerable does not contain definition of and best extension method overloads has some invalid arguments. i can see only two overloads of ToDictionary Method in my visual studio tooltip sort of documentation whereas i have come across more than two overloads of ToDictionary on the web
Edit Here is exact Error message at compile time
Error 13 'System.Collections.Generic.IEnumerable<AnonymousType#1>'
does not contain a definition for
'ToDictionary' and the best extension
method overload
'System.Linq.Enumerable.ToDictionary<TSource,TKey>(System.Collections.Generic.IEnumerable<TSource>,
System.Func<TSource,TKey>,
System.Collections.Generic.IEqualityComparer<TKey>)'
has some invalid arguments

The compiler message makes the error clear: There is no method ToDictionary which can accept the arguments and types specified.
The mistake here is in specifying the type arguments on ToDictionary. The MSDN documentation defines the extension method as ToDictionary<TKey, TSource>. The source in your example is IEnumerable<AnonymousType#1>, but you have specified a type of List<string>.
To correct the error, omit the type arguments; the compiler will infer the correct types. You can additionally combine the Select and ToDictionary transformations into a single statement:
var contacts = dr.mktDoctorContacts
.GroupBy(x => x.ContactType)
.ToDictionary(
y => y.Key,
y => y.Select(x => x.Contact).ToList());

Rewrote your code (and added .AsEnumerable()):
var dictionary = dr.mktDoctorContacts
.GroupBy(x => x.ContactType)
.AsEnumerable()
.ToDictionary(
i => i.Key,
i => i.Select(x => x.Contact).ToList()
)
);

Don't run that group operation in the database, it'll cause the elements of each group to be fetched in separate roundtrips.
ILookup<string, string> contacts = dr.mktDoctorContacts
.ToLookup<Contact, string, string>(x => x.ContactType, x => x.Contact);

Related

GroupBy OrderBy Linq - invalid column

I am trying to build a very simple LinQ query used to return a json to my client.
the following works:
_context.MyTable
.GroupBy(g => new { type= g.TypeId })
.Select(x => x.Count())
However, I would like to retun the count list ordered by type so I wrote the following but it didn't work:
_context.MyTable
.GroupBy(g => new { type= g.TypeId })
.OrderBy(o => o.Key.type)
.Select(x => x.Count())
It returns a 'invalid column name "type"'
I don't get it, the orderby is occuring after the groupBy, I am using the key properly.
It looks like, the orderBy needs the criteria in the Slect statement to work properly.
For example, the following works:
_context.MyTable
.GroupBy(g => new { type= g.TypeId })
.OrderBy(o => o.Key.type)
.Select(x => {x.Count(), x.Key.type})
But it does not return what i want, I just want to get the count values ordered by type.
Any directions why I get this error.
I am using EF Core if it can help.
S.
Although EF Core 2.1 introduced improvements to LINQ GroupBy translation, the implementation is still far from perfect and produces exceptions in many scenarios due to invalid SQL generation. Your scenario is just one of them and is not working even with the recent at this time EF Core 2.1.1 bits.
The first thing you should do is to submit it to the EF Core issue tracker, so they know and fix it when possible.
The problem seems to be related to the key property aliasing (it also doesn't work if you use the "normal" .GroupBy(e => e.TypeId).OrderBy(g => g.Key)). The current workaround I've found is to use anonymous type key having the same property name(s) as the source(s):
_context.MyTable
.GroupBy(e => new { e.TypeId })
.OrderBy(g => g.Key.TypeId)
.Select(g => g.Count())

NEST MultiGet search all types possible?

I have got unique document ids (across all types) and I would like to check which document already exists in elasticsearch index. I try to search
var duplicateCheck = _elasticClient
.MultiGet(m => m.GetMany<object>(notices.Select(s => s.Id)).Fields("Id"));
but it returns wrong result - every document has set found property to false.
update
there is workaround here
var exisitngDocIds = _elasticClient.Search<ZPBase>(s => s
.AllTypes()
.Query(q => q.Ids(notices.Select(z=>z.Id)))
.Fields("Id")
.Take(notices.Count)
);
notices = notices.Where(q => !exisitngDocIds.Hits.Any(s => s.Id == q.Id)).ToList();
From the Multi Get API documentation I realized that you can use something similar to the following code to solve your problem:
var response = _elasticClient.MultiGet(m => m
.Index(MyIndex)
.Type("")
.GetMany<ZPBase>(noticeIds));
Note the empty string passed as the Type.

LINQ How to Average an internal list

What is the LINQ syntax for the Average need below. Both Select and SelectMany fail me.
I can Max() and Sum() my internal list, but Average() wont compile.
The JSON version of the simple list looks like
[{"Week":6, "Matches":[{"Game":189},{"Game":149},{"Game":132}]} ....
var hiGame = games.Max(g => g.Matches.Max(m => m.Game)); // ok
var hiSeries = games.Max(g => g.Matches.Sum(m => m.Game)); // ok
var ave = games.Average(g => g.Matches.SelectMany(m => m.Game)); // no go
The type arguments for method 'System.Linq.Enumerable.SelectMany(System.Collections.Generic.IEnumerable, System.Func>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
I think you want your SelectMany on the outside:
var ave = games.SelectMany(g => g.Matches) // Flatten to a sequence of matches
.Average(m => m.Game); // Average by value of Game

Count in lambda expression

I am trying to run a query where I get the name of locations and the number of items in that location. So if i have a program that contains 3 locations I want to know how many programs are in that location..I need to use this with a lambda expression or linq to entities.
return Repository.Find(x => x.Location.Name.Count())...clearly missing something here.
we'll just assume I have a Program entity with ProgramID, ProgramName, LocationName...need to know how many programs are in at a location
You can do it like this:
return repository.Count(x => x.Location == "SomeLocation");
Do you want to know the counts for all locations at once?
var locCounts = Repository.GroupBy(prog => prog.Location.Name).ToLookup(g => g.key, g => g.Count());
if you will repositoryPattern, use this code
Clients.Where(p => p.DateOfArrival >= DateTime.Now.AddDays(-3) && p.DateOfArrival <= DateTime.Now.AddDays(3)).Select(p => p.ID).Count()
Repository Pattern

Selecting on a many table using Linq

I have a recipe table that has a related ingredients table
on one to many basis.
How do I select using Linq ingredients
that have a ingredientName column and it should contain
a specified word.
This is what I tried.
IQueryable<OurRecipes.Domain.Linq2Sql.Recipe> recipes = _dbctx.Recipes.AsQueryable();
foreach (string word in searchdata.Keywords)
{
recipes = recipes.Where(r => r.RecipeTitle.Contains(word));
recipes = recipes.Where(r => r.Ingredients.Where(i => i.IngredientName.Contains(word)));
}
I get cannot convert type 'etc' to bool error.
Any ideas
Malcolm
The error lies here:
recipes = recipes.Where(r => r.Ingredients.Where(i => i.IngredientName.Contains(word)));
The condition inside Where must return a boolean, in this case, the r.Ingredients.Where(i => i.IngredientName.Contains(word)) will not return a boolean, and hence the error.
This is how you can fix the problem:
recipes = recipes.Where(i => i.Ingredients.Any(row=>row.IngredientName.Contains(word)));
r.Ingredients.Where(i => i.IngredientName.Contains(word)));
replace with
r.Ingredients.Any(i => i.IngredientName.Contains(word)));
Btw, I like SQL like syntax more as it more netural. The same:
from r in _dbctx.Recipes
where r.Ingredients.Any(i => i.IngredientName.Contains(word)));
select r;
This will select all recipies that has ingredients with name contains word.

Resources