here is my problem. I'm trying to select a list of records after a specific one, so starting from this value I want to select the next one (and not the starting value).
My "filter" is a primary key, something like "NP-A6666".
Here is my code actually:
var listVU = _context.AVu
.OrderByDescending(r => r.UpdateDate)
.Select(x => new AVut
{
VuId = x.VuId
})
.Take(50)
.AsNoTracking()
.ToListAsync();
return await listVU;
I would do something like:
var listVU = _context.AVu
.OrderByDescending(r => r.UpdateDate)
".StartingFromButExluding(p => p.VuId == "NP-A6666")"
.Select(x => new AVut
{
VuId = x.VuId
})
.Take(50)
.AsNoTracking()
.ToListAsync();
return await listVU;
So I will get listVU as a list of 50 values right after NP-A6666 (from NP-A6667 to NP-A6717 ordered for UpdateDate).
Use SkipWhile
var listVU = _context.AVu
.OrderByDescending(r => r.UpdateDate)
.SkipWhile(p => !p.VuId.Equals("NP-A6666"))
.Select(x => new AVut
{
VuId = x.VuId
})
.Take(50)
.AsNoTracking()
.ToListAsync();
Skipwhile runs sequentially through the enumerable, skipping elements where the predicate returns true - once the predicate returns false, in this case when the VuID = "NP-A6666", the remaining elements are returned as a new enumerable.
If you then want to get everything up to VuID.Equals("NP-A6717"), you can do the same thing with TakeWhile instead of Take(50):
var listVU = _context.AVu
.OrderByDescending(r => r.UpdateDate)
.SkipWhile(p => !p.VuId.Equals("NP-A6666"))
.Select(x => new AVut
{
VuId = x.VuId
})
.TakeWhile(p => !p.Equals("NP-A6717"))
.AsNoTracking()
.ToListAsync();
And If you're wanting to exclude the row that the SkipWhile is stopping on, just do .Skip(1) right after the SkipWhile(p => !p.VuId.Equals("NP-A6666"))
var listVU = _context.AVu
.OrderByDescending(r => r.UpdateDate)
.SkipWhile(p => !p.VuId.Equals("NP-A6666"))
.Skip(1)
.Select(x => new AVut
{
VuId = x.VuId
})
.Take(50)
.AsNoTracking()
.ToListAsync();
Related
I Have this code. It works fine but when I have two same maximal values it appear 2 times. So I need to use OrderBy. But I dont know how. Thanks for any help.
IQueryable<PerformanceRealization> pr = _context.PerformanceRealization
.Where(u => u.Deadline == _context.PerformanceRealization
.Where(x => x.GroupRealizationId == u.GroupRealizationId)
.Max(x => x.Deadline)
)
.Select(u => u);
Here is the SQL code with GROUP BY
SELECT PR.GroupRealizationId
FROM Stores.PerformanceRealization PR
LEFT JOIN Stores.GroupRealization ON Stores.GroupRealization.Id = PR.GroupRealizationId
WHERE PR.Deadline = (SELECT MAX(Deadline)
FROM Stores.PerformanceRealization PR2
WHERE PR.GroupRealizationId = PR2.GroupRealizationId)
GROUP BY PR.GroupRealizationId
You can select the first object from the group
IQueryable<PerformanceRealization> pr2 = pr
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.First());
If you need a specific object from the group, then you can order by another column
IQueryable<PerformanceRealization> pr2 = pr
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.OrderBy(x => x.SomeColumn).First());
for SomeColumn having the smallest value. For the greatest value, use OderByDescending instead.
Of course, you can integrate this approach into the first query:
IQueryable<PerformanceRealization> pr = _context.PerformanceRealization
.Where(u => u.Deadline == _context.PerformanceRealization
.Where(x => x.GroupRealizationId == u.GroupRealizationId)
.Max(x => x.Deadline)
)
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.OrderBy(x => x.SomeColumn).First());
Note, you don't need to have a Select at the end like .Select(u => u). Since it has no effect, you can just drop it.
If your EF Core version cannot handle it (as revealed in a comment), then transition to LINQ-to-Objects with AsEnumerable(), but do the filtering in EF Core to minimize the number of records sent to the front-end:
IQueryable<PerformanceRealization> pr = _context.PerformanceRealization
.Where(u => u.Deadline == _context.PerformanceRealization
.Where(x => x.GroupRealizationId == u.GroupRealizationId)
.Max(x => x.Deadline)
)
.AsEnumerable() // <===== transition from LINQ-to-EF-Core to LINQ-to-Objects
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.OrderBy(x => x.SomeColumn).First());
I have the data in the source table.
And I want to get this kind of result in list using lambda expression and Entity Framework. I don't know how to do it. I need to get top 3 rows in for each CategoryId.
Probably using something like this:
context.GroupBy(x => x.CategoryId)
.Select(group => new {
CategoryId = group.Key,
NameId = group.Select(x => x.NameId),
group.OrderByDescending(e => e.Count).Take(3)
})
.ToListAsync()
var list = context
.GroupBy(x => x.CategoryId)
.SelectMany(group => group.OrderByDescending(e => e.Count).Take(3))
.OrderByDescending(e => e.Count)
.ToListAsync();
If you want an anonymous type:
var list = context
.GroupBy(x => x.CategoryId)
.SelectMany(group => group.OrderByDescending(e => e.Count).Take(3))
.Select(x => new
{
x.CategoryId,
x.NameId,
x.Count
})
.OrderByDescending(x => x.Count)
.ToListAsync();
I have the following code:
var test = _fitDbContext.MvLatestTestResult
.Include(r => r.LastTest)
.Include(r => r.LastTest.Testrun)
.Include(r => r.LastTest.Testrunconfig)
.Where(r => r.LastTest.Testrunconfig.Started.Value.Hour >= 0 && r.LastTest.Testrunconfig.Started.Value.Hour < 6)
.Where(r => r.LastTest.Testrun.Userc == "build")
.Where(r => r.ProductId == productId)
.GroupBy(r => r.LastTest.Testrunconfig.Started.Value.Date)
.OrderByDescending(r => r.Key.Date)
.Take(3)
.ToDictionary(group => group.Key, group => group.GroupBy(r => r.Configfilename));
Variable test looks like this:
You can see that LastTest is null. If I remove .OrderByDescending(r => r.Key.Date), it contains value.
Why does OrderByDescending remove LastTest value?
EDIT
Interesting thing I just found out. If I change order of GroupBy and OrderBy, everything works as expected. The problem is that OrderBy is executed with all records and takes a long time.
var test = _fitDbContext.MvLatestTestResult
.Include(r => r.LastTest)
.Include(r => r.LastTest.Testrun)
.Include(r => r.LastTest.Testrunconfig)
.Where(r => r.LastTest.Testrunconfig.Started.Value.Hour >= 0 && r.LastTest.Testrunconfig.Started.Value.Hour < 6)
.Where(r => r.LastTest.Testrun.Userc == "build")
.Where(r => r.ProductId == productId)
.OrderByDescending(r => r.Key.Date)
.GroupBy(r => r.LastTest.Testrunconfig.Started.Value.Date)
.Take(3)
.ToDictionary(group => group.Key, group => group.GroupBy(r => r.Configfilename));
I have the following nHibernate query that select a course based on its course id and then return selected fields for the course object on the initial fetch, and the query executes with no issues.
MatchMode option = ...
CourseItem courseAlias = null;
TeacherItem teacherAlias = null;
var query = session.QueryOver<CourseItem>()
.JoinAlias(c => c.Teacher, () => teacherAlias)
.Where(c => c.CourseID.IsInsensitiveLike(strNumber, option))
.SelectList(list => list
.Select(c => c.CourseID).WithAlias(() => courseAlias.CourseID)
.Select(c => c.IsActive).WithAlias(() => courseAlias.IsActive)
.Select(c => c.CourseDesc).WithAlias(() => courseAlias.CourseDesc)
.Select(c => c.Teacher).WithAlias(() => courseAlias.Teacher))
.TransformUsing(Transformers.AliasToBean<CourseItem>())
.List<CourseItem>();
I wanted to go a step further with the query to only return a partial teacher object, let's say i just wanted to return the ID and Name. So, I updated the projected list to as follows:
var query = session.QueryOver<CourseItem>()
.JoinAlias(c => c.Teacher, () => teacherAlias)
.Where(c => c.CourseID.IsInsensitiveLike(strNumber, option))
.SelectList(list => list
.Select(c => c.CourseID).WithAlias(() => courseAlias.CourseID)
.Select(c => c.IsActive).WithAlias(() => courseAlias.IsActive)
.Select(c => c.CourseDesc).WithAlias(() => courseAlias.CourseDesc)
.Select(c => c.Teacher.ID).WithAlias(() => courseAlias.Teacher.ID)
.Select(c => c.Teacher.Name).WithAlias(() => courseAlias.Teacher.Name))
.TransformUsing(Transformers.AliasToBean<CourseItem>())
.List<CourseItem>();
The query doesn't work because nHibernate has no idea how to resovled based on Teacher.ID and Teacher.Name. Any thoughts on whether it's possible to NOT fetch the entire child object back to a parent object?
I've tried the following query and it works this is not my fully desired outcome
var query = session.QueryOver<CourseItem>(() => courseAlias)
.JoinAlias(() => courseAlias.Teacher, () => teacherAlias)
.Where(() => courseAlias.CourseID.IsInsensitiveLike(strNumber, option))
.SelectList(list => list
.Select(() => courseAlias.CourseID)
.Select(() => courseAlias.IsActive)
.Select(() => courseAlias.CourseDesc)
.Select(() => teacher.ID)
.Select(() => teacher.Name))
.List<object[]>();
I can query the right values but unable to transform it back correctly to the Course / teacher data type.
Any thoughts?
thanks!
We can indeed use custom transformer. There is one, which I am using for a really very very deep projections (inlcuding dynamic objects - 5.1.13. component, dynamic-component)
DeepTransformer<TEntity>
Take it (if needed adjust it) and your final query could be like this
// just the last lines are different
var query = session.QueryOver<CourseItem>()
.JoinAlias(c => c.Teacher, () => teacherAlias)
.Where(c => c.CourseID.IsInsensitiveLike(strNumber, option))
.SelectList(list => list
.Select(c => c.CourseID).WithAlias(() => courseAlias.CourseID)
.Select(c => c.IsActive).WithAlias(() => courseAlias.IsActive)
.Select(c => c.CourseDesc).WithAlias(() => courseAlias.CourseDesc)
// the native WitAlias would not work, it uses expression
// to extract just the last property
//.Select(c => c.Teacher.ID).WithAlias(() => courseAlias.Teacher.ID)
//.Select(c => c.Teacher.Name).WithAlias(() => courseAlias.Teacher.Name))
// so we can use this way to pass the deep alias
.Select(Projections.Property(() => teacherAlias.ID).As("Teacher.ID"))
.Select(Projections.Property(() => teacherAlias.Name).As("Teacher.Name"))
// instead of this
// .TransformUsing(Transformers.AliasToBean<CourseItem>())
// use this
.TransformUsing(new DeepTransformer<CourseItem>())
And in case, that your aliases do match to property names, that transformer will built the object tree...
I got a LINQ query with Entity Framework (EF) and getting a list of items. Now I want to create a dictionary with the incrementing index of the item and the item itself.
I have it like this:
result = context
.Items
.Where(b => !b.Deleted)
.OrderBy(b => b.Name)
.ToDictionary(COUNTHERE, b => b.Name)
So the dictionary have to look like this:
1: "item1"
2: "item2"
3: "item5"
4: "item10"
5: "item100"
I think what you need is to have the item name as the key instead the count as the key, because if there is two items that have the same count, it will throw exception that the key has been added.
Then you can Use GroupBy before ToDictionary so that you can count it.
result = context
.Items
.Where(b => !b.Deleted)
.GroupBy(x => x.Name)
.ToDictionary(g => g.Key, g => g.Count())
.OrderBy(g => g.Key);
based on your updated comment, then what you need is
result = context
.Items
.Where(b => !b.Deleted)
.OrderBy(b => b.Name)
.AsEnumerable()
.Select((v,i) => new { i, v.Name })
.ToDictionary(g => g.i + 1, g => g.Name);
Note that you need to add AsEnumerable so that the Select clause works as linq to object (Select that accept index is not supported in L2S).
Just use:
int count = 0;
var result = context
.Items
.Where(b => !b.Deleted)
.OrderBy(b => b.Name)
.ToDictionary(b => ++count, b => b.Name);
An alternative way of achieving this is:
var sortedNames = context
.Items
.Where(b => !b.Deleted)
.Select(b => b.Name)
.OrderBy(b => b.Name)
.ToArray();
result = Enumerable.Range(1, sortedNames.Length)
.ToDictionary(i => i, i => sortedNames[i - 1]);
To get zero-based numbering, use Enumerable.Range(0, sortedNames.Length) and sortedNames[i] instead.