I have next code, taking Last and Pre-Last params of elemensts in DB:
var result = _context.Contacts.Where(conts => conts.CreatorUserId == _userManager.GetUserId(this.User))
.Select(conts => new
{
conts.ID,
conts.Mobile,
conts.Email,
conts.Facebook,
conts.StateId,
conts.CreatorUserId,
conts.Birthday,
conts.Description,
conts.Name,
conts.Photo,
conts.SecondName,
Tags = conts.Tags.Select(d=> d.UserTag.Emoji),
NpaId = conts.NpaInfo.NpaId,
PartnerPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.MyPV).FirstOrDefault(),
GroupPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.GroupPV).FirstOrDefault(),
LevelPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault(),
PartnerPv = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(1).Select(x => x.MyPV).FirstOrDefault(),
Level = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault(),// conts.NpaInfo.PerformanceBonusLevelId,
GroupPv = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(1).Select(x => x.GroupPV).FirstOrDefault(),
EntryDate = conts.NpaInfo.EntryDate,
ExpirationDate = conts.NpaInfo.ExpirationDate
});
In fact the part :
PartnerPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.MyPV).FirstOrDefault(),
GroupPvPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.GroupPV).FirstOrDefault(),
LevelPrev = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault()
converts to something like this in 1 request (show you only part for one block):
SELECT TOP(1) [t0].[MyPV]
FROM (
SELECT [x0].[MyPV], [x0].[DataMonth]
FROM [NpaDatas] AS [x0]
WHERE [conts.NpaInfo].[ID] = [x0].[NpaInfoId]
ORDER BY [x0].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
) AS [t0]
ORDER BY [t0].[DataMonth] DESC
) AS [PartnerPvPrev], (
SELECT TOP(1) [t1].[GroupPV]
FROM (
SELECT [x1].[GroupPV], [x1].[DataMonth]
FROM [NpaDatas] AS [x1]
WHERE [conts.NpaInfo].[ID] = [x1].[NpaInfoId]
ORDER BY [x1].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
) AS [t1]
ORDER BY [t1].[DataMonth] DESC
) AS [GroupPvPrev], (
SELECT TOP(1) [t2].[PerformanceBonusLevelId]
FROM (
SELECT [x2].[PerformanceBonusLevelId], [x2].[DataMonth]
FROM [NpaDatas] AS [x2]
WHERE [conts.NpaInfo].[ID] = [x2].[NpaInfoId]
ORDER BY [x2].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
) AS [t2]
ORDER BY [t2].[DataMonth] DESC
) AS [LevelPrev]
I dont want to repeat the same part multiple times:
conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1)
So, if I do like this :
PrevBuffer = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Skip(1).Take(1).Select(
param => new
{
param.MyPV,
param.GroupPV,
param.PerformanceBonusLevelId
}
),
It will display many separate requests in output for each row like:
SELECT [x0].[MyPV], [x0].[GroupPV], [x0].[PerformanceBonusLevelId]
FROM [NpaDatas] AS [x0]
WHERE @_outer_ID1 = [x0].[NpaInfoId]
ORDER BY [x0].[DataMonth] DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY
The same is about this part :
Tags = conts.Tags.Select(d=> d.UserTag.Emoji)
Will get multiple selects like:
SELECT [d.UserTag].[Emoji]
FROM [ContactTags] AS [d]
LEFT JOIN [UserTags] AS [d.UserTag] ON [d].[UserTagId] = [d.UserTag].[ID]
WHERE @_outer_ID = [d].[ContactId]
Can it be optimized somehow?
Doing something like this will improve the query significantly.
var result = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth).Take(2).ToArray();
PartnerPvPrev = result.Skip(1).Take(1).Select(x => x.MyPV).FirstOrDefault();
GroupPvPrev = result.Skip(1).Take(1).Select(x => x.GroupPV).FirstOrDefault();
LevelPrev = result.Skip(1).Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault();
PartnerPv = result.Take(1).Select(x => x.MyPV).FirstOrDefault();
Level = result.Take(1).Select(x => x.PerformanceBonusLevelId).FirstOrDefault();
GroupPv = result.Take(1).Select(x => x.GroupPV).FirstOrDefault();
You should select the repetitive parts first and use these in the subsequent query. This is much easier in query syntax, using the let
keyword:
var result = from conts in _context.Contacts
where conts.CreatorUserId == _userManager.GetUserId(this.User)
let monthsSorted = conts.NpaInfo.NpaData.OrderByDescending(x => x.DataMonth)
let firstMonth = monthsSorted.FirstOrDefault()
let prevMonth = monthsSorted.Skip(1).FirstOrDefault()
select new
{
conts.ID,
conts.Mobile,
conts.Email,
conts.Facebook,
conts.StateId,
conts.CreatorUserId,
conts.Birthday,
conts.Description,
conts.Name,
conts.Photo,
conts.SecondName,
Tags = conts.Tags.Select(d=> d.UserTag.Emoji),
NpaId = conts.NpaInfo.NpaId,
PartnerPvPrev = prevMonth.MyPV,
GroupPvPrev = prevMonth.GroupPV,
LevelPrev = prevMonth.PerformanceBonusLevelId,
PartnerPv = firstMonth.MyPV,
GroupPv = firstMonth.GroupPV,
Level = firstMonth.PerformanceBonusLevelId,
EntryDate = conts.NpaInfo.EntryDate,
ExpirationDate = conts.NpaInfo.ExpirationDate
};
You should use a GroupBy :
class Program
{
static void Main(string[] args)
{
Conts conts = new Conts();
List<NpaDatas> data = conts.NpaInfo.NpaDatas
.OrderByDescending(x => x.DataMonth)
.GroupBy(x => x.DataMonth).Select(x => x.FirstOrDefault()).ToList();
//To get the second latest use followng
NPaDatas results = data.Skip(1).FirstOrDefault();
}
}
public class NpaDatas
{
public string NpaInfoId { get; set; }
public DateTime DataMonth { get; set; }
public PV PartnerPv { get; set; }
public PV PerformanceBonusLevelId { get; set; }
public PV GroupPv { get; set; }
}
public class PV
{
//data not specified
}
public class Conts
{
public NpaInfo NpaInfo { get; set; }
}
public class NpaInfo
{
public string ID { get; set; }
public List<NpaDatas> NpaDatas { get; set; }
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.