Getting unique values using Linq to Entities - c#

I'm using EF and have a context from which I can get a collection of Item objects using _inventoryContext.Items. Now, these item objects have a string value called Carrier. Let's say there are 5 items in Items collection and they have these Carrier values:
"A", "A", "B", "C", "C"
How do I use _inventoryContext.Items to get back the unique carrier values?
"A", "B", "C"
Note that
var carriers = _inventoryContext.Items.Select(i => i.Carrier).Distinct();
does not work; I get "The method 'Distinct' is not supported" with no inner exception.
I'm using SQL Server 2008 Express. Items is a DataServiceQuery<Item> and its Carrier property is a string.

Your example should work, but here is another way you can try
List<string> carriers = _inventoryContext.Items.GroupBy(i => i.Carrier)
.Select(i => i.Key)
.ToList();

Related

string.Contains could not be translated

This is my first post in this site.
I have a list of vehicles in my database and every vehicle has a Vin (License Plate Number, in example "6TRJ244", it is a string value).
I receive a list of search values, in example "A", "B","J"
I need to filter the vehicles which Vin Contains one of the search values.
In example if I have three vehicles with Vin: Vehicle1_Vin = "123AJ", Vehicle2_Vin = "123BJ", Vehicle3_Vin = "777CR"
If I receive as search values "X", "A","C" I should return Vehicles 1 and 3
With LINQ I am trying to do something like this
var searchParams = new List<string>() { "A", "B", "C"};
vehicles = vehicles.Where((vehicle) => searchParams.Any((searchParam) => vehicle.Vin.Contains(searchParam)));
But I receive this error message
"System.InvalidOperationException: The LINQ expression 'searchParam => EntityShaperExpression:
ProjectAlpha.BusinessObjects.Models.Vehicle
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
.Vin.Contains(searchParam)' 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."
Thanks ins advance!
You could try use functions if you are using net core try with something like this
IQueryable<T> nightClub = nightClub.Where(nc => EF.Functions.Like(nc.Name, "%Dfox%");
It is not clear what collection type vehicles variable is so better introduce new variable or transfer IEnumerable to same type as source collection (ToArray/ToList etc):
var searchParams = new List<string>() { "A", "B", "C"};
var filtered = vehicles.Where(vehicle => searchParams.Any(vehicle.Vin.Contains));

C# filter Dictionary of list of class based on class property

I have this dictionary Dictionary<string, List<Payments>>, which holds employees, each employee having a list of payments. The Payments class has a string property named PayCategoryId. I want to filter this dictionary and get only the employees with payments having some specific PayCategoryId values and for each employee only those payments. I'm pretty sure this can be achieved by using LINQ, but I have almost zero experience with LINQ, so need your help.
The original (unfiltered) dictionary has 76 items (employees). The employee which I'll use as an example has 27 payments, some of them having the required PayCategoryId.
What I've done:
List with the required PayCategoryId:
var payCategoriesID = new List<string> (){ "a", "b", "c" };
Semi-filter the dictionary with this LINQ (I'm sure it's a mess, but is working!):
var result = dict.Where(o => o.Value.Where(x => payCategoriesID.Contains(x.PayCategoryId)).Any()).ToDictionary(mc => mc.Key, mc => mc.Value);
The semi-filtered resulted dictionary has only 34 items. The employees having no payments with the required PayCategoryId were filtered out. But my example employee still has all 27 payments in the list. I need his list to be filtered too and have only the payments having PayCategoryId = one of the IDs from payCategoriesID list.
Of course, the example employee is just an example, all employees should be filtered.
Can you help, please?
Adrian
You can use Select() to project into an enumerable of anonymous type and get only the value you want, then build back a dictionary.
var match = dict
.Select(kv => new
{
Employee = kv.Key,
Payments = kv.Value.Where(p => payCategoriesID.Contains(p.PayCategoryId))
})
.Where(emp => emp.Payments.Any())
.ToDictionary(k => k.Employee, v => v.Payments);
The first step creates an object with key and filtered values, then the Where() remove the empty lists. That way you only iterate through the ids list once (per element on the dictionary).
Also, not really related, but the Any() method has an overload which takes a predicate, so instead of
o.Value.Where(x => payCategoriesID.Contains(x.PayCategoryId)).Any()
you can do directly
o.Value.Any(x => payCategoriesID.Contains(x.PayCategoryId))
Same goes for other LINQ methods such as Count(), First(), FirstOrDefault(), Last() and more.
var result = dict.Where(o => o.Value.Where(x => payCategoriesID.Contains(x.PayCategoryId)).Any()).ToDictionary(mc => mc.Key, mc => mc.Value.Where(t=> payCategoriesID.Contains(t.PayCategoryId)));

C# - Linq join returns unexpected number of elements

I have data from two data structures that I would like to join with respect to date. Each data structure contains 88 values and every date in one structure has a corresponding date in the other structure. However, when I try to join them, the list with the joined result contains 90 values. In other words the result contains two extra values. When I inspect the values in the joined list it seems that it contains two extra values at the start of the list that are identical to the first "expected" joined value.
Any ideas what might be wrong?
Here is the join expression that I am using:
//Joins vib and RPM with respect to date
var joinedVibRPM = serie.Value.Values.Join(
RPMSeriesOne.Values,
_vib => _vib.DateTime,
_rpm => _rpm.DateTime,
(_vib, _rpm) => new { vib = _vib.Value, rpm = _rpm.Value }).ToList();
You can explain the result when your input sets have duplicate entries. Consider for example this join of two list with four items each (using strings, not DateTime for better readability):
var items1 = new { "A", "B", "C", "C" };
var items2 = new { "A", "B", "B", "C" };
If you perform this join:
var joinedItems =
from item1 in items1
join item2 in items2 on item1 equals item2
select item1 + item2;
Your result will be:
{ "AA", "BB", "BB", "CC", "CC" }
You will find "BB" twice because it is repeated in the secod list and "CC" twice because it is repeated in the first list. In total you will get 5 items.
If you have any duplicate dates in either structure then one element in one structure will match 2 (or more) elements in the other structure. This will give you more than 88 results.
Check your structures for distinct values:
serie.Value.Values.Distinct().Count();
and
RPMSeriesOne.Values.Distinct().Count();
One of these results will likely be less than 88 indicating the presence of duplicates.

In Entity Framework 5 CodeFirst, how to create a query that will return when any pair of values are found?

I have an unknown number of complex keys passed into my function at runtime. They will be structured like this:
var keys = new List<List<string>>
{
new List<string> { "1", "a" },
new List<string> { "2", "b" },
new List<string> { "3", "c" }
};
The inner list will always have two values. The outter list could have n values. I am attempting to query a table where records match any of the pairs in the List. I tried this query like this:
var filtered =
dataContext.T.Where(
s => keys.Any(k =>
k[0] == s.Column0
&& k[1] == s.Column1));
At this point, LinqToEntities fails because it seems that linq is unable to process lists (or arrays?) inside an .Any() method.
This is the error I get when I run this code:
"LINQ to Entities does not recognize the method 'System.String get_Item(Int32)' method, and this method cannot be translated into a store expression."
So my question is, how can I query for records that match any pair of values in the lists? I can change anything about the structure as long as I can query for any in a set of pairs.
Thanks for any guidance.
Don't think you can use any enumerable like that in linq 2 entities.
One workaround would be to concatenate your pairs, with a "should never appear" string in the middle.
var concatenatedkeys = keys.Select(m => m[0] + "~" + m[1]).ToList();
var filtered =
dataContext.T.Where(s => concatenatedKeys.Contains(
s.Column0 ?? string.Empty +
"~" +
s.Column1));
The answer does solve the problem that I posed in the question. However, I ran into a similar issue once I needed to compare values across linked entities.
The concatenation solution ran into problems with this scenario:
var filtered =
dataContext.T.Where(s => concatenatedKeys.Contains(
s.AnotherEntity.Column0 ?? string.Empty +
"~" +
s.AnotherEntity.Column1));
To solve this, I ended up using LinqKit to create the .Where() expression using the PredicateBuilder.

How to Union List<List<String>> in C#

I'm having a List<List<String>>, and which contains
{ {"A" , "B" },
{"C" , "D" }
}
I need to union all the innerlist into another list
So the resulting List<String> will contain
{"A","B","C","D"}
Now im using for loop to do this
Is there any way to do this Using LINQ or Lambda Expression.
Please help me to do this.
Thanks in advance.
Not Exactly a Union, but you can try this
YourList.SelectMany(l=>l).Distinct()
List<List<string>> collections = new List<List<string>>()
{
new List<string>(){"A" , "B" },
new List<string>() {"C" , "D" }
};
var list = collections.SelectMany(x => x).ToList();
SelectMany builds up a expression tree that when evaluated flattens the list of list to a single list of combined members.
ToList forces the expression tree to be evaluated and which results in a List.
If you want to eliminate duplicates you can add a Distinct call before the call to 'ToList()'
You can use the SelectMany extension method.
List<List<String>> masterList = { {"A" , "B" }, {"C" , "D" } };
IEnumerable<string> results = masterList.SelectMany(l => l);
var result = myLists.SelectMany(l => l);
How about Aggregate?
myLists.Aggregate((left, right) => left.Union(right));
To me, this is more expressive than using SelectMany, because it is telling you exactly what you are doing: Aggregate your list of lists by calling union on them all.
Just for kicks:
(from list in theList from e in list select e).Distinct().ToList()
This is of course the same solution as #Alexander Taran's, just with query syntax instead of lambda syntax. (Or at least it should be – I don't have my LINQPad handy.)

Categories