I am using a predicate builder class and I need to invoke the contains method on an array of strings so in the code below instead of radio I would be passing in an array of strings:
wherePredicate = wherePredicate.Or(m => m.MediaType.Contains("Radio"));
the full code section:
if (param.iMediaGroupID > 0)
{
var wherePredicate = PredicateBuilder.False<MediaChannelModel>();
var ss = new NeptuneRepository<Lookup_MediaTypes>();
var mediagroups = ss.FindWhere(m => m.MediaGroupID == param.iMediaGroupID).Select(m => m.Name);
//problem area
wherePredicate = wherePredicate.Or(m => mediagroups.Contains(m.MediaType));
predicate = predicate.And(wherePredicate);
}
mediaGroups is: ["Radio","Tv","Magazine"]
If m.MediaType is any of these values then the predicate is true.
Is there a way to do this in C#?
I suspect you want something like:
wherePredicate = wherePredicate.Or(m => array.Contains(m.MediaType));
Or perhaps:
wherePredicate = wherePredicate.Or(m => array.Any(x => m.MediaType.Contains(x)));
If neither of those are what you're after, please clarify your requirements.
EDIT: The problem you're now facing is that you're not actually asking whether an array contains the value. You're asking whether a query contains a value. If you change it to an actual array, you may well find it works:
var mediagroups = ss.FindWhere(m => m.MediaGroupID == param.iMediaGroupID)
.Select(m => m.Name)
.ToArray();
However, if these are querying the same database, you'd be better off trying to do this in some kind of join.
Jon Skeet's answer worked perfectly for me. I had been struggling to make the .Contains search for a substring in a string array against the database, rather than try to find a substring in a single C# string object. Thank you!
Here's the modified code that worked for me:
var predicate = PredicateBuilder.False<ClientXMemberDetail>();
predicate = predicate.Or(x => strArrselectedCustomMemberNumbers.Any<string>(y => x.MemberID.Contains(y)));
CustomSearchMembersAlreadyMatched = ClientXContext.ClientXMemberDetails
.AsExpandable()
.Where(predicate)
.ToList()
.Select(r => r.MemberID.ToString()).ToList();
(ClientXContext above is an instance of the ObjectContext class, strArrselectedCustomMemberNumbers is a string array, ClientXMemberDetails is ObjectSet, where ClientXMemberDetail is the EntityObject)
Edit: Anonymized my client's name
Related
I am writing a piece of code in order to get values from the server. There are multiple code lines and need to do the same thing using lambda expressions. This is the code I have tried and please help to rewrite this code using lambda expressions.
var newDocuments = result?.DocumentQueryResults.OrderBy(d => context.GetParams().GetAllDocumentIds().ToList().IndexOf(d.Document.Id)).ToList();
var test = new List<HealthRecord>();
foreach (DocumentQueryResult item in newDocuments)
{
test.Add(item.Document);
}
I believe you're looking for something like this:
// Cache the sort parameters, as suggested by Caius Jard:
var sortParams = context.GetParams()
.GetAllDocumentIds()
.AsEnumerable()
.Select((id, index) => new { id, index })
.ToDictionary(x => x.id, x => x.index);
var test = result?.DocumentQueryResults
.OrderBy(d => sortParams[d.Document.Id])
.Select(d => d.Document)
.ToList();
Basically I have an object with 2 different properties, both int and I want to get one list with all values from both properties. As of now I have a couple of linq queries to do this for me, but I am wondering if this could be simplified somehow -
var componentsWithDynamicApis = result
.Components
.Where(c => c.DynamicApiChoicesId.HasValue ||
c.DynamicApiSubmissionsId.HasValue);
var choiceApis = componentsWithDynamicApis
.Select(c => c.DynamicApiChoicesId.Value);
var submissionApis = componentsWithDynamicApis
.Select(c => c.DynamicApiSubmissionsId.Value);
var dynamicApiIds = choiceApis
.Union(submissionApis)
.Distinct();
Not every component will have both Choices and Submissions.
By simplify, I assume you want to combine into fewer statements. You can also simplify in terms of execution by reducing the number of times you iterate the collection (the current code does it 3 times).
One way is to use a generator function (assuming the type of items in your result.Components collection is Component):
IEnumerable<int> GetIds(IEnumerable<Component> components)
{
foreach (var component in components)
{
if (component.DynamicApiChoicesId.HasValue) yield return component.DynamicApiChoicesId.Value;
if (component.DynamicApiSubmissionsId.HasValue) yield return component.DynamicApiSubmissionsId.Value;
}
}
Another option is to use SelectMany. The trick there is to create a temporary enumerable holding the appropriate values of DynamicApiChoicesId and DynamicApiSubmissionsId. I can't think of a one-liner for this, but here is one option:
var dynamicApiIds = result
.Components
.SelectMany(c => {
var temp = new List<int>();
if (c.DynamicApiChoicesId.HasValue) temp.Add(c.DynamicApiChoicesId.Value);
if (c.DynamicApiSubmissionsId.HasValue) temp.Add(c.DynamicApiSubmissionsId.Value);
return temp;
})
.Distinct();
#Eldar's answer gave me an idea for an improvement on option #2:
var dynamicApiIds = result
.Components
.SelectMany(c => new[] { c.DynamicApiChoicesId, c.DynamicApiSubmissionsId })
.Where(c => c.HasValue)
.Select(c => c.Value)
.Distinct();
Similar to some of the other answers, but I think this covers all your bases with a very minimal amount of code.
var dynamicApiIds = result.Components
.SelectMany(c => new[] { c.DynamicApiChoicesId, c.DynamicApiSubmissionsId}) // combine
.OfType<int>() // remove nulls
.Distinct();
To map each element in the source list onto more than one element on the destination list, you can use SelectMany.
var combined = componentsWithDynamicApis
.SelectMany(x => new[] { x.DynamicApiChoicesId.Value, x.DynamicApiSubmissionsId.Value })
.Distinct();
I have not tested it but you can use SelectMany with filtering out the null values like below :
var componentsWithDynamicApis = result
.Components
.Select(r=> new [] {r.DynamicApiChoicesId,r.DynamicApiSubmissionsId})
.SelectMany(r=> r.Where(p=> p!=null).Cast<int>()).Distinct();
The first query returns a list of string, and I am passing them into another table to find corresponding items, but nothing happens. no error message or nothing
var classIds = _contextSpecRepo.Get(x => x.cId.Equals(cId)).Select(x => x.classNames).Distinct().ToList();
// issue happens in the following query
var classes= Repository.Get(x => x.Id.Equals(classIds)).ToList();
The call to Equals, which takes object, hides the problem: you are comparing a single Id to a list of Ids, rather than checking if the Id is present in a collection. This compiles, but yields no result.
Here is how you can fix it:
var classes= Repository.Get(x => classIds.Any(y => y == x.Id)).ToList();
or
var classes= Repository.Get(x => classIds.Contains(x.Id)).ToList();
If you must do it in 2 queries then you have to use contains
var classes= Repository.Get(x => classIds.Contains(x.Id)).ToList();
A better solution would be to use a join on the tables.
you can also skip .ToList()
var classes= Repository.Get(x => classIds.Contains(x.Id));
I have the following code:
var languages = _languageService
.GetAll()
.Select(x => (((LanguageViewModel) new LanguageViewModel().InjectFrom(x))))
.ToList();
When executing this, languages becomes, as expected, a collection of LanguageViewModel objects:
What I am trying to do is, when selecting, also convert the object's Code property to uppercase, as so:
var languages = _languageService
.GetAll()
.Select(x => (((LanguageViewModel) new LanguageViewModel().InjectFrom(x)).Code = x.Code.ToUpper()))
.ToList();
I'm expecting the languages object to have multiple LanguageViewModels in it but it looks like this:
My guess is the fact that I'm using a statement like Select(x => (new Object().Property = Value)) it selects the Property. But then, how can I return an object with one of its properties changed? Using object initializer before inject is not an option as it gets overriden, using it after the Inject is not possible, as it is not casted yet, so I got to the solution here which does not seem to work. Any advice greatly appreciated.
You can't write the lambda body as a single expression that does what you want, but you don't need to. You can put multiple statements in a lambda:
var languages = _languageService
.GetAll()
.Select(x => {
var lvm = (LanguageViewModel)new LanguageViewModel().InjectFrom(x);
lvm.Code = x.Code.ToUpper();
return lvm;
})
.ToList();
Your Select line could be rewritten to
.Select(x =>
{
var vm = new LanguageViewModel().InjectFrom(x);
vm.Code = vm.Code.ToUpper();
return vm;
})
Why does this yield an empty set?
Object[] types = {23, 234, "hello", "test", true, 23};
var newTypes = types.Select(x => x.GetType().Name)
.Where(x => x.GetType().Name.Equals("Int32"))
.OrderBy(x => x);
newTypes.Dump();
When you do your select you're getting an IEnumerable<String>. Then you're taking the types of each string in the list (which is all "String") and filtering them out where they aren't equal to "Int32" (which is the entire list). Ergo...the list is empty.
Equals works just fine, it's your query that isn't correct. If you want to select the integers in the list use:
var newTypes = types.Where( x => x.GetType().Name.Equals("Int32") )
.OrderBy( x => x );
Reverse the order of the operations:
var newTypes = types.Where(x => x is int)
.OrderBy(x => x)
.Select(x => x.GetType().Name);
(Notice this also uses a direct type check instead of the rather peculiar .GetType().Name.Equals(…)).
The thing with LINQ is you've got to stop thinking in SQL terms. In SQL we think like this:-
SELECT Stuff
FROM StufF
WHERE Stuff
ORDER BY Stuff
That is what your code looks like. However in LINQ we need to think like this :-
FROM Stuff
WHERE Stuff
SELECT Stuff
ORDER BY Stuff
var newTypes = types.Select(x => x.GetType().Name)
.Where(x => x.Equals("Int32"))
.OrderBy(x => x);
This doesn't work because the Select statement will convert every value in the collection to the name of the underlying type of that value. The resulting collection will contain only string values and hence they won't ever have the name Int32.