Linq Join Multiple Criteria (Number not known beforehand) - c#

I need to join multiple criteria inside a linq query, I have a criteria box like below :
Currently Im using a query than can only handle a single tag :
var c = *text after the t:*
var r = rs.Returns.Where(x => x.Lines.Any(y => y.Tags.Any(z => z.Name.Contains(c))));
I need something like (this may be incorrect) :
var r = rs.Returns.Where(x => x.Lines.Any(y => y.Tags.Any(z => z.Name.Contains(*1st Tag*)) && y.Tags.Any(z.Name.Contains(*2nd Tag*)))); .. etc
So that all the tags the Line has are searched and AND is applied. Is there an easy way of achieving such a thing?
Many thanks in advance.

var r = rs.Returns.Where(x => x.Lines.Any(y => searchTags.All(stag => y.Tags.Any(z => z.Name.Contains(stag)))));
searchTags should contain all tags to search for. No need to use a loop.

I think you are looking for something like this:
List<string> tags = new List<string>() { "tag1", "tag2" };
var query = rs.Returns.AsEnumerable();
foreach(string tag in tags)
{
string tmp = tag;
query = query.Where(x => x.Lines.Any(y => y.Tags.Any(z => z.Name.Contains(tmp))));
}

Related

how use like in sql on linq c#

this not work
string[] DATE_Group = { "2020", "2021" }; //changing values
var query = _context.c10
.Where(u => DATE_Group.Any(s => u.ON_DATE.Contains(s)))
.ToList()
.Select(u => new
{
User_NumberID = u.User_NumberID.ToString(),
}).ToList();
I use this u.ON_DATE.Contains("2020") and work but not list or array only one value
in sql SELECT * from C10 where ON_DATE like '%2020%' or ON_DATE like '%2021%'
and in ON_DATE column content like this 1-3-2023 1-1-2021 5-1-2020
this error when used
enter image description here
Use this below code for your linq where statement.
var myVar=context.Students.where(x=>x.Name.Contains("John")).SingleOrDefault();
I think this is a better way to get the data:
var from = new DateTime(2020,1,1);
var to = new DateTime(2022,1,1);
var query = _context.c10
.Where(u => u.ON_DATE > from && u.ON_DATE < to )
...
EF Core cannot use Any with local collections (with small excpetion), only Contains is supported.
I would suggest to use function FilterByItems. And use in query:
string[] DATE_Group = { "2020", "2021" }; //changing values
var query = _context.c10
.FilterByItems(DATE_Group, (u, s) => u.ON_DATE.Contains(s), true)
.Select(u => new
{
User_NumberID = u.User_NumberID.ToString()
})
.ToList();

How to select * and calculate field in Entity Framework?

I want to select all pictures and calculate IsAnnotated field, but how I can select * fields and apply this IsAnnotated field?
Because in this example for now only selected IsAnnotated. Do we have a possibility to prevent manually write something like Id = picture.Id, title = picture.Title?
var picture = await _dbContext.Pictures
.Select(picture => new Picture
{
IsAnnotated = _dbContext.Annotations.Any(x => x.PictureId == picture.Id),
})
.Where(s => ids.Contains(s.Id))
.ToListAsync();
First, select the Pictures you want by ids list:
var pictures = _dbContext.Pictures
.Where(s => ids.Contains(s.Id));
Second, calculate the IsAnnotated field with foreach - this is not a case of 'select', this is an update case. (Convert to 'List' for using the ForEach linq function, you can use the foreach statement instead):
pictures.ToList().ForEach(a => a.IsAnnotated = _dbContext.Annotations.Any(x => x.PictureId == a.Id));
You can do something like this.
Var pictures = _dbcontext.Pictures.Where(x=> IDs.Contains(x.id));
var annotations = await pictures.Join(_dbContext.annotation, pic => pic.id, ann => ann.pictureId, (pic, ann) => new
{
Annotation = ann.IsAnnotated
}.ToListAsync();
Or instead an anonymous type you can pass a model if you want.
Sorry if it's not readable but I wrote it from my phone!! 🙏

Is there a way to have multiple likes generated dynamically from an array of string values in EF?

I've set up a search textbox where the search will grab every word individually and search through a field using Contains.
Is there a way to search an array of string through Contains?
//Keep in mind that the array would be generated dynamically through textbox
string[] searchWords = { "hello", "world", "today" };
var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => a.Title.Contains(searchWords));
searchWords obiviously does not work but trying to show what I want to achieve. searchWords[0] works because it is just one word.
I also tried below as suggested in other links but now the WHERE clause does not show up in query when i run debugger or profiler:
`var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => searchWords.Any(w => a.Title.Contains(w)));
`
It seems like Entity Framework Core does not translate .Any and .All with .Contains in the above query to SQL statements. Instead it loads all otherwise matching data and does the search in memory.
If you want to find Articles which contain all search words in the Title you could dynamically add .Where conditions (I had a test database with Persons and a Comment field):
var query = (IQueryable<Person>)dbContext.Persons
.Include(p => p.TaxIdentificationNumber);
foreach (var searchWord in searchWords)
{
query = query.Where(p => p.Comment.Contains(searchWord));
}
var persons = query.ToList();
But if you want to find articles which contain any of the search words then you would need an OR in the .Where clause.
Written manually it would look like this:
.Where(p => p.Comment.Contains(searchWords[0]) || p.Comment.Contains(searchWords[1]))
But you can build the expression dynamically:
Expression<Func<Person, bool>> e1 = p => p.Comment.Contains(searchWords[0]);
Expression<Func<Person, bool>> e2 = p => p.Comment.Contains(searchWords[1]);
Expression<Func<Person, bool>> e3 = p => p.Comment.Contains(searchWords[2]);
var orExpression1 = Expression.OrElse(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
var orExpression2 = Expression.OrElse(orExpression1, Expression.Invoke(e3, e1.Parameters[0]));
var finalExpression = Expression.Lambda<Func<Person, bool>>(orExpression2, e1.Parameters);
and use it like this:
var persons = dbContext.Persons.Where(finalExpression).ToList();
as a function:
Expression<Func<Person, bool>> BuildOrSearchExpression(string[] searchWords)
{
// searchWords must not be null or empty
var expressions = searchWords.Select(s => (Expression<Func<Person, bool>>)(p => p.Comment.Contains(s))).ToList();
if (expressions.Count == 1) return expressions[0];
var orExpression = expressions.Skip(2).Aggregate(
Expression.OrElse(expressions[0].Body, Expression.Invoke(expressions[1], expressions[0].Parameters[0])),
(x, y) => Expression.OrElse(x, Expression.Invoke(y, expressions[0].Parameters[0])));
return Expression.Lambda<Func<Person, bool>>(orExpression, expressions[0].Parameters);
}
and use it
var persons = dbContext.Persons
.Include(p => p.TaxIdentificationNumber)
.Where(BuildOrSearchExpression(searchWords))
.ToList();
If you exchange the .OrElse with .AndAlso all search words must be found like with multiple .where clauses.
When I did some research I also stumbled upon the PredicatedBuilder http://www.albahari.com/nutshell/predicatebuilder.aspx and this SearchExtension https://stackoverflow.com/a/31682364/5550687. But I have not tried them and I don't know if they work with EF Core.

Trying to simplify LINQ expression

I'm trying to simplify a LINQ expression but no matter what i try I'm unable to get it to work
var filterProfileIds = filter.Profiles.Select(s => s.ProfileId);
var newList = new List<FileMedia>();
foreach (var item in filterProfileIds)
{
newList.AddRange(query.Where(w => w.Profiles.Select(s => s.ProfileId).Contains(item)));
}
newList.AddRange(query.Where(w => !w.Profiles.Any()));
query = newList.AsQueryable();
query is of type "FileMedia" and has a relation to Profiles.
So what i want is all the results from the query that has the same profiles that filter.profiles has AND i also want all the results from the query that doesnt have any profiles at all.
Try as the below:
var filterProfileIds = filter.Profiles.Select(s => s.ProfileId);
query = query.Where(w =>
!w.Profiles.Any() ||
w.Profiles.Any(i => filterProfileIds.Contains(i.ProfileId))
).ToList();
If I understand correctly the requirement, you could use a combination of Any and All extension methods like this:
query = query.Where(m => !m.Profiles.Any() ||
filterProfileIds.All(id => m.Profiles.Any(p => p.ProfiledId == id)));
This is if you wish to get the items with exact the same profiles as the filter.
If you indeed want to get the item with any profile contained in the filter, then you could use this instead:
query = query.Where(m => !m.Profiles.Any() ||
m.Profiles.Any(p => filterProfileIds.Contains(p.ProfiledId));
Maybe something like this:
query = (from item in filter.Profiles.Select(s => s.ProfileId)
from fileMedia in query
where fileMedia.Profiles.Select(q => q.ProfileId).Contains(item)
select fileMedia).
Concat(query.Where(w => !w.Profiles.Any())).AsQueryable();

How to put an Entity Framework query result into a List

How to Put the following query result into a List
var result = from c in sb.Swithches_SW_PanalComponents
select new { c.ID,c.SW_PanalComponents.ComponentsName,c.ComponentValue };
FINAL EDIT
Based on your last comment, this is all you ever needed
List<Swithches_SW_PanalComponents> result =
sb.Swithches_SW_PanalComponents.ToList();
which of course is identical to
var result = sb.Swithches_SW_PanalComponents.ToList();
EDIT
Based on your comments, I think this is what you want:
List<SW_PanalComponents> result = sb.Swithches_SW_PanalComponents
.Select(c => new SW_PanalComponents { /* initialize your fields */ })
.ToList();
END EDIT
The ToList method is what you want. But consider using dot notation. For simple queries like this, it's much cleaner and trimmer.
var result = sb.Swithches_SW_PanalComponents
.Select(c => new { c.ID, c.SW_PanalComponents.ComponentsName, c.ComponentValue })
.ToList();
Also note that, if you're just trying to execute your query immediately, and only need to enumerate over it, you can also call AsEnumerable()
var result = sb.Swithches_SW_PanalComponents
.Select(c => new { c.ID, c.SW_PanalComponents.ComponentsName, c.ComponentValue })
.AsEnumerable();
The advantage here is that result is a less specific type—IEnumerablt<T>.
Like this:
var result =(from c in sb.Swithches_SW_PanalComponents
select new
{ c.ID,
c.SW_PanalComponents.ComponentsName,
c.ComponentValue
}).ToList();
That what i came with finally:
List<Swithches_SW_PanalComponents> MyList = new List<Swithches_SW_PanalComponents>();
var Result = from all in sb.Swithches_SW_PanalComponents
select all
;
MyList.AddRange(Result.ToList<Swithches_SW_PanalComponents>());

Categories

Resources