How to select * and calculate field in Entity Framework? - c#

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!! 🙏

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();

C# Linq - Refactoring ForEach Loop with Sub List

Am trying to refactor some data in order to display some charts.
I can't seem to figure out why using the following, it lists all the values at the top rather than being sequential like the source data.
var categories = VehicleSales.Select(v => v.name).Distinct().ToList();
var refactoredResults = new List<StackedColumnChart>();
foreach (var category in categories)
{
var subresult = VehicleSales.Where(x => x.vehicleType == category)
.GroupBy(x => x.vehicleType)
.Select(gcs => new StackedColumnChart
{
Category = category,
Values = gcs.Select(x => (int)x.data).DefaultIfEmpty(0).ToList()
}).ToList();
refactoredResults.AddRange(subresult);
}
Source Data:
Then the actual results and expected results:
Thanks in advance!
You can do that without loop and selecting a distinct values, just use GroupBy method and map each group to StackedColumnChart using Select
var refactoredResults = VehicleSales
.GroupBy(s => s.Category)
.Select(g => new StackedColumnChart
{
Category = g.Key,
Values = g.Select(s => s.Value).ToList()
})
.ToList();
If the original data is not sorted and you'll need to sort the values by week number, you can use OrderBy clause before selecting a values Values = g.OrderBy(s => s.WeekNumber).Select(s => s.Value).ToList()

How to filter a sublist inside parent and return parent with sublist filtered

I want to create a linq to sql query that will return a list of objects with a sublist that has been filtered.
It sounds easy but I'm not sure how to make this to work
Here the SQL Query which returns what I want:
select * from Texts t inner join Translations tt on t.TranslationId = tt.Id
inner join Pages p on tt.Id = p.TranslationId and tt.NeutralText = p.TitleNeutralTextId
where t.LanguageId = 1
Now I have to write this with linq.
What I've done so far is:
var query = this.Queryable() // Page entity
.AsNoTracking()
.Include(x => x.TitleTranslation.Texts);
return (from m in query
from l in m.TitleTranslation.Texts
where m.TitleTranslation.Texts.Any(l => l.LanguageId == 1)
select m);
But it didn't work because I got the sublist with all languages instead of language with id #1 only.
Thanks for helping,
David
Any specific reason you are writing query? Either you can use Eager Loading of EF to load all the child tables, Or below Linq statement can fetch the required result
var result = texts.Join(translations, t => t.TranslationId, tt => tt.Id, (t, tt) => new {t, tt})
.Join(pages, ttt => new { Id = ttt.tt.Id, NeutralTextId = ttt.tt.NeutralText }, p => new { Id = p.TranslationId, NeutralTextId = p.TitleNeutralTextId }, (ttt, p) => new {ttt, p})
.Where(tttt => tttt.ttt.t.LanguageId == 1);
Here replace texts, translations and pages with actual dbContext entities collection property.
I think you must try lime this. this will work for you .
This will be similar to sql query
One way to do this .
var result = from m in Texts
join Translations on Texts.TranslationId = Translation.Id
Join Pages on Translations.NeutralText = Pages.NeutralText
where Texts.LanguageId = 1
select m
There an other way to do this using entity framework
var result =
this.Queryable().AsNoTracking().Include(x=>x.Translations).Where(x=>x.LanguageId= 1)
I found the solution I wanted thanks to Hasnain Bukhari.
The solution was to start from the text table, assign the filter, include the desired Entity (Page) and put the results into memory (ToList()). Then select pages. It will give the result I want in the order I have to.
var query = textService.Queryable()
.AsNoTracking()
.Include(x => x.Translation.Pages)
.Where(x => x.LanguageId == languageId).ToList();
return query.SelectMany(x => x.Translation.Pages);

Entity framework use already selected value saved in new variable later in select sentance

I wrote some entity framework select:
var query = context.MyTable
.Select(a => new
{
count = a.OtherTable.Where(b => b.id == id).Sum(c => c.value),
total = a.OtherTable2.Where(d => d.id == id) * count ...
});
I have always select total:
var query = context.MyTable
.Select(a => new
{
count = a.OtherTable.Where(b => b.id == id).Sum(c => c.value),
total = a.OtherTable2.Where(d => d.id == id) * a.OtherTable.Where(b => b.id == id).Sum(c => c.value)
});
Is it possible to select it like in my first example, because I have already retrieved the value (and how to do that) or should I select it again?
One possible approach is to use two successive selects:
var query = context.MyTable
.Select(a => new
{
count = a.OtherTable.Where(b => b.id == id).Sum(c => c.value),
total = a.OtherTable2.Where(d => d.id == id)
})
.Select(x => new
{
count = x.count,
total = x.total * x.count
};
You would simple do
var listFromDatabase = context.MyTable;
var query1 = listFromDatabase.Select(a => // do something );
var query2 = listFromDatabase.Select(a => // do something );
Although to be fair, Select requires you to return some information, and you aren't, you're somewhere getting count & total and setting their values. If you want to do that, i would advise:
var listFromDatabase = context.MyTable.ToList();
listFromDatabase.ForEach(x =>
{
count = do_some_counting;
total = do_some_totalling;
});
Note, the ToList() function stops it from being IQueryable and transforms it to a solid list, also the List object allows the Linq ForEach.
If you're going to do complex stuff inside the Select I would always do:
context.MyTable.AsEnumerable()
Because that way you're not trying to still Query from the database.
So to recap: for the top part, my point is get all the table contents into variables, use ToList() to get actual results (do a workload). Second if trying to do it from a straight Query use AsEnumerable to allow more complex functions to be used inside the Select

Linq Join Multiple Criteria (Number not known beforehand)

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))));
}

Categories

Resources