Linq query with multiple where's [duplicate] - c#

This question already has answers here:
Multiple WHERE clause in Linq
(3 answers)
Closed 2 years ago.
I am trying the to query my Status Update repository using the following
var result = (from s in _dataContext.StatusUpdates
where s.Username == "friend1" && s.Username == "friend2" etc...
select s).ToList();
Instead of using s.Username == "friendN" continuously is there anyway I can pass a list or array or something like that rather that specifying each one, or can I use a foreach loop in the middle of the query.
Thanks

If you only need to check whether the Username property has some specified value, you can create a list of the values and then use method such as All or Any to check if some condition holds for any/all elements of the array.
Your example looks a bit suspicious though - the user name s.Username cannot be equal to multiple different strings. Did you want to check whether it is equal to any of the (specified) names? That could be written like this:
var friends = new[] { "friend1", "friend2", ... };
var result =
from s in dc.StatusUpdates
where friends.Any(fr => s.Username == fr)
select s;
This returns all status updates such that the Username property is equal to any of the specified friend names (specified as an array, but you could use any IEnumerable<string>).

Yo could do it like this:
IQueryable<s> query= _dataContext.StatusUpdates;
foreach (var item in names)
{
query = query.Where(p=>p.Username == item);
}
List<s> result = query.ToList();

I think I mucked with some data types of yours but this should be close:
var names = new List<string>();
// populate names
var updates = new List<StatusUpdate>();
// populate updates
var result = (from s in updates
where names.Contains(s.ToString())
select s).ToList();

Related

SQL Selection to Array in C#

I am querying in C# for the first time, so please forgive my ignorance. I want to query a table, then place the results in an array/dict/dataframe to then be accessed later. I am unable to run the final code on my end, so this is more of an exercise in setting up the queries for when the final code (a chatbot) works.
Here is the code that should work to get boiling points and melting points seperately. Assume that casnumber is declared in advance (let's just call it str '753')
boiling_point = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.boiling_point).FirstOrDefault();
melting_point = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.metling_point).FirstOrDefault();
How would I get the results of the query to an array/dict/dataframe instead?
dict = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select cdls.boiling_point,
cdls.melting_point).FirstOrDefault();
Ideally, I would want {(boiling_point : 200F), (melting_point : 100F)} as output, or something similar in a table/df/array. There are 30+ attributes in the table, so a way to assign key-value pairs or create a dataframe from the query for each attribute queried would be ideal.
Get a list of Tuples like this
var tuples = (from cdls in ADVISORCHEMICALS
where cdls.casnumber == casnumber
select (cdls.boiling_point, cdls.melting_point))
.ToList();
tuples will be a list of tuples (ex. List<(string boiling_point, string melting_point)>)
for (var tuple in tuples)
{
var boiling_point = tuple.boiling_point;
var melting_point= tuple.melting_point;
}

How to order list based on some id found in another list c#?

I know there are plenty of question about this topic but none of them seems to solve my answer (or at least from what i have found) pardon me if this is a duplicate question.
I have a list that i gather from SQL containing two properties SequenceId and Relevant:
var sequenceList = await context.SequenceDB.Where(c => c.PeopleId == peopleId).Select(c => {
SequenceId = c.SequenceId,
Relevant = c.Relevant
}).OrderBy(c => c.Relevant).ToListAsync();
Then i have another list like so:
var secondList = await context.Activity.ToListAsync();
FYI
the second list has multiple properties (hence column in the database) and one of them is SequenceId pointing to that SequenceId in SequenceDB.
What i want is to order the secondList based on the order of GUID's in the sequenceList.
BUT:
I just need to order them NOT exclude them from the list. And i don't want to exclude any of the elements from secondList
The result will be a list of Activity with as first elements the ones from sequenceList and then the rest
If you think this is a duplicate question please point me to the right one and i'll delete this one.
It seems simple even though is not for me.
You can join the lists using an outer join, so something like this should work.
First, number each row in secondList so we can retain the order for items which don't match those in the sequenceList.
var indexedSecondList = secondList.Select((e, index) => new { e, index });
(from r in indexedSecondList
join s in sequenceList on r.e.SequenceId equals s.SequenceId into tmp
from t in tmp.DefaultIfEmpty()
orderby t != null ? 0 : 1 , // Sort the entries that are in SequenceList first
t != null ? t.Relevant : (System.Guid?) null , // Then sort by Relevant
r.index // Finally sort by original order in secondList
select r.e).ToList();

Check if text contains any string item from list of string c# linq

I am trying to fetch a list of users after filtering by their name.
Query:
string filter="alex, faheem, Cohen";
var filterArr=filter.Split(new []{','},StringSplitOptions.RemoveEmptyEntries).Select(f=>f.Trim()).ToList();
var users= (from u in DbContext.Users
where filterArr.Any(y=> u.Name.Contains(y)) select u);
This gives me the error:
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.
I can't use filterArr.Contains(x.Name) because Name column contains both first name and second name. Just Like in list above their is an item "alex" and I have a name "Alex Hales" combined in Name column. So If I use filterArr.Contains(x.Name) it will not give me the result.
Any help will be much appreciated.
I'm not sure this is possible in a single statement like this. It's too complicated for the poor parsing stuff to work out.
However, you can get an IQueryable(), then iterate over your filters append these as individual WHERE clauses, then these should get added to the SQL properly later.
Something like this:
//this just gets a reference the DbSet, which implements IQueryable<User>
var queryable = _dbContext.Users;
//iterate over the filters and add each as a separate WHERE clause
foreach(var f in filters)
{
//this just adds to the existing expression tree..
queryable = queryable.Where(u=>u.Name.Contains(f));
}
//this will actually hit the database.
var results = queryable.ToList();
This should generate something like this in SQL (entirely pseudo-code)
select
u.*
from
users u
where
(u.username like "%Sue%")
or (u.username like "%Bob%")
Hope this helps...
I think you can do something like this
string filter = "alex, faheem, Cohen";
var filterArr = filter.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(f => f.Trim()).ToList();
var users = _dbContext.Users.Where(x => filterArr.Any(n => n.Contains(x.Name))).ToList();
UPDATE
For your requirement following query will work fine.
string filter = "Alex, faheem, Cohen";
var filterArr = filter.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(f => f.Trim())
.ToList();
var users = _dbContext.Users
.Where(x => filterArr.Any(n => x.UserName.Contains(n))).ToList();
If user has searched for "alex" and in Name (database column) there is "Alex Hales". users query will return the user "Alex Hales".

LINQ 2 SQL - using a C# entity collection and SqlMethods.Like together

I have a collection of headers, each which contains a collection of objects, each of which contains a collection of metadata key value pairs. eg
> Header
> -> Object
> -> Key value pair
> -> Key value pair
> -> Object
> -> Key value pair
> -> Key value pair
I want to return all headers, which contain an object, which contains a certain key value pair in the metadata, using SQL wildcards (using SqlMethods.Like).
I have written a LINQ 2 SQL query below with two levels of subqueries which handles the scenario
string filePath = "ab%cd";
var dbHeaders = from h in _repository.GetHeaders()
where
(from o in h.Objects
where
(from mdp in o.MetaDataPairs
where mdp.Key == Constants.FilePath && SqlMethods.Like(mdp.Value.ToLower(), filePath))
select mdp
).Any()
select o).Any()
select h;
This works fine.
The problem arises when I have a list of possible search values to search on. Ie I want to find objects containing a metadata value from a list of possible matches, not just a single match. I tried the below.
var filePaths = new List<string> { "ab%cd", "ef%gh" };
var dbHeaders = from h in _repository.GetHeaders()
where
(from o in h.Objects
where
(from mdp in o.MetaDataPairs
where mdp.Key == Constants.FilePath && filePaths.Any(fp => SqlMethods.Like(mdp.Value.ToLower(), fp))
select mdp
).Any()
select o).Any()
select h;
but because SQLMethods.Like is contained within Filepaths.Any() it doesn't work. as it has to occur natively in the LINQ 2 SQL query.
How can I modify the top query to match, using SQL Like operator, so that it checks against a list of string search tokens, not a single one?
UPDATE: Error message below
Assert.IsFalse failed. An unexpected error occurred: LINQ to Entities
does not recognize the method 'Boolean Like(System.String,
System.String)' method, and this method cannot be translated into a
store expression.
The issue is, as you've mentioned, that once you put the SqlMethods.Like in the filePaths.Any it throws an exception.
That's because SqlMethods.Like is not supported in linq-to-entity, and filePath is an entity.
You need to, somehow, dynamically create multiple OR statements with SqlMethods.Like.
I've found a very similar question and an interesting answer that should help:
How can I add variable count of SqlMethods.Like() in one query?
The solution takes advantage of PredicateBuilder from C# 6.0 in a Nutshell.
I believe you could adapt your code into something like the following:
I didn't test the code, ofcourse.
var filePaths = new List<string> { "ab%cd", "ef%gh" };
var likeExpression = PredicateBuilder.False<MetaDataPairClassName>();
foreach (string filePath in filePaths)
{
likeExpression = likeExpression.Or(mdp =>
SqlMethods.Like(mdp.Value.ToLower(), filePath));
}
var dbHeaders = from h in _repository.GetHeaders()
where
(from o in h.Objects
where
(from mdp in o.MetaDataPairs
.Where(mdp.Key == Constants.FilePath)
.Where(likeExpression))
select mdp
).Any()
select o).Any()
select h;

Compare two list if match found update first list property

I have two lists first is
DataTable DtblDiseaseList = this.GetDisease();
List<DiseaseModel> model = DtblDiseaseList.DataTableToList<DiseaseModel>();
And second is
var userDisease = DiseaseManagementBA.getUserDisease(UserID).DataTableToList<DiseaseModel>();
Here I want to compare userDisease with model list if match found then I want to update the property of first list i.e. model. In DiseaseModel class there is on property i.e. IsChecked. I want to set true to this property if match found.
The first "if match found" can be done using a Join. This enumerates each of your lists and returns the results from model in which the "match" condition is found. I am presuming there the "match" is matching IDs as I don't know the actual criteria.
var result = (from m in model
where join d in userDisease on m.ID == d.ID
select m).ToList();
Once you have the list, its a matter of iterating and setting the value. I'm sort of assuming you're using LinqToSql with the InsertOnSubmit and the SubmitChanges methods.
foreach (var r in result)
{
r.IsChecked = true;
this.InsertOnSubmit(r);
}
this.SubmitChanges();
I should note that this will work, but results from the first join are enumerated into memory, they are not updated by the database.
You could do it simply as following:
model.Intersect(userDisease).ToList().ForEach(_ => _.IsChecked = true);
Hello guys my problem is solved by this Linq query
model.Where(x => userDisease.Any(z => z.DiseaseId == x.DiseaseId)).Select(x => { x.IsChecked = true; return x; }).ToList();

Categories