Pivot and Unpivot in LINQ Core - linq

I am new to LINQ core. I want to write a query in LINQ Core for doing PIVOT and UNPIVOT on table. I have written SQL query for it but need help in converting to LINQ query. I have searched few articles but it didnt helped.
Below is my SQL Query for PIVOT and UNPIVOT which I need to convert to LINQ Query:
SELECT ResourceName,
max(ENText)as ENText,
max(FRText)as FRText,
max(ZHText)as ZHText,
max(DEText)as DEText,
max(ITText)as ITText,
max(JAText)as JAText,
max(PTText)as PTText,
max([PT-BRText]) as [PT-BRText],
max(RUText) as RUText,
max(ESText) as ESText,
max(SVText) as SVText into #temp FROM
GenericLanguageTranslation
PIVOT
(
max(Translation) FOR LanguageID IN (
ENText,
ZHText,
FRText,
DEText,
ITText,
JAText,
PTText,
[PT-BRText],
RUText,
ESText,
SVText)
) AS Tab2
group by ResourceName
order by 1
SELECT NEWID() as Id,ResourceName, [LanguageID],[Translation]-- into #GenericLanguageTranslation
FROM #temp
UNPIVOT
(
[Translation]
FOR [LanguageID] IN
(
ENText,
ZHText,
FRText,
DEText,
ITText,
JAText,
PTText,
[PT-BRText],
RUText,
ESText,
SVText
)
) AS UnpivotTranslation
Can any one help me in this?

I am able to get PIVOT for the above query using below LINQ :
var languageTranslation = await _genericlanguageTranslationService.GetAllLanguageTranslation();
var query = languageTranslation.GroupBy(c => c.ResourceName)
.Select((g, i) => new
{
ResourceName = g.Key,
RowNumber = i + 1,
ENText = g.Where(c => c.LanguageId == "ENText").Max(c => c.Translation),
FRText = g.Where(c => c.LanguageId == "FRText").Max(c => c.Translation),
ZHText = g.Where(c => c.LanguageId == "ZHText").Max(c => c.Translation),
DEText = g.Where(c => c.LanguageId == "DEText").Max(c => c.Translation),
ITText = g.Where(c => c.LanguageId == "ITText").Max(c => c.Translation),
JAText = g.Where(c => c.LanguageId == "JAText").Max(c => c.Translation),
PTText = g.Where(c => c.LanguageId == "PTText").Max(c => c.Translation),
PT_BRText = g.Where(c => c.LanguageId == "PT-BRText").Max(c => c.Translation),
RUText = g.Where(c => c.LanguageId == "RUText").Max(c => c.Translation),
ESText = g.Where(c => c.LanguageId == "ESText").Max(c => c.Translation),
SVText = g.Where(c => c.LanguageId == "SVText").Max(c => c.Translation)
})
.AsEnumerable()
.OrderBy(x => x.ResourceName);
But I also need to find a way to UNPIVOT.

Related

Linq How to group joined queries

I am newbee and can join two datasets. I want to group these by OrderNo query. How can I manage that?
var result = context.Order
.Join(context.OrderDetails
, od => od.OrderId
, o => o.OrderId
, (o, od) => new {
o.OrderNo, od.ProductName, o.OrderDate
})
.Select(s => s);
try this
var result = context.Order
.Join(context.OrderDetails
, od => od.OrderId
, o => o.OrderId
, (o, od) => new {
o.OrderNo, od.ProductName, o.OrderDate
})
.GroupBy(p => new{
o.OrderNo
})
.Select(s => s);

How do I exclude certain parts of a .Include on a condition?

We are trying to exclude certain data from our queries based on a condition, but we can't seem to get it right. Our current code looks like this:
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(y => y.RequestApps.SelectMany(x => x.RequestAppDataChoices)
.Where(s => s.AppDataChoiceDl.Contains(groupName))
.Where(a => a.RequestApps.AppProvisioningCompleteTime != null)
.Where(aa => aa.RequestApps.AppTeamCompleteTime == null)
.Where(ab => !ab.RequestApps.AppStatus.Contains("Rejected")).Any());
This is fine as long as we are trying to pull all of the "RequestApps" with each set of "RequestInformation", however if we want to pull just specific applications based on conditions, it doesn't work. We want to only show the request apps based on the the conditions above (The appdatachoicedl contains "groupname", the completetime != null while the other completetime IS null, and that the status is not rejected), but instead, we are getting all the request information that matches those conditions.
I tried something like this, but it still doesn't quite give me the results I need. It gives me random blank results as well:
var PullDataV2 = from reqInfo in _context.RequestInformation
join RA in _context.RequestApps on reqInfo.ReqNum equals RA.ReqNum
join RADC in _context.RequestAppDataChoices on RA.PkId equals RADC.RequestAppsId
where RADC.AppDataChoiceDl == groupName
select new RequestInformation()
{
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
RequestApps = reqInfo.RequestApps,
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus
};
I hope I'm making sense here - I only want the requestapps based on the conditions, not all the request information that is those conditions. RequestApps is a part of the RequestInformation class.
Edit:
Piggybacking off of Roberts comments, I modified his code to look like this, but I am struggling with the last line - I need to be able to make sure that "AppDataChoiceDL" which is a member of RequestAppDataChoices (which is a member of RequestApps) is equal to groupName
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(a => a.AppDataChoiceDl.Contains(groupName))
.Where(b => b.RequestApps.AppProvisioningCompleteTime != null)
.Where(c => c.RequestApps.AppTeamCompleteTime == null)
.Any(n => !n.RequestApps.AppStatus.Contains("Rejected"))).Select(reqInfo => new RequestInformation
{
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus,
RequestApps = reqInfo.RequestApps
.Where(a => a.AppProvisioningCompleteTime != null)
.Where(b => b.AppTeamCompleteTime == null)
.Where(x => !x.AppStatus.Contains("Rejected"))
.Where(b => b.RequestAppDataChoices.Where(a => a.AppDataChoiceDl == groupName))
});
This throws an error not being able to convert IENUmerable to bool.. maybe I'm selecting my RequestAppDataChoices wrong?
This assumes you have a RequestInformationDto class that closely resembles your RequestInformation class:
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(x => x.AppDataChoiceDl.Contains(groupName))
.Where(x => x.RequestApps.AppProvisioningCompleteTime != null)
.Where(x => x.RequestApps.AppTeamCompleteTime == null)
.Where(x => !x.RequestApps.AppStatus.Contains("Rejected")).Any())
.Select(reqInfo => new RequestInformationDto {
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
RequestApps = reqInfo.RequestApps
.Where(app => app.AppProvisioningCompleteTime != null)
.Where(app => app.AppTeamCompleteTime == null)
.Where(app => !app.AppStatus.Contains("Rejected")).Any())
.ToList()
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus
});
I just noticed this part of your query, which should probably be reworked (or removed) as well:
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(x => x.AppDataChoiceDl.Contains(groupName))
.Where(x => x.RequestApps.AppProvisioningCompleteTime != null)
.Where(x => x.RequestApps.AppTeamCompleteTime == null)
.Where(x => !x.RequestApps.AppStatus.Contains("Rejected")).Any())
With Robert McKee's help, I was able to come up with this, that does work:
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(a => a.AppDataChoiceDl.Contains(groupName))
.Where(b => b.RequestApps.AppProvisioningCompleteTime != null)
.Where(c => c.RequestApps.AppTeamCompleteTime == null)
.Any(n => !n.RequestApps.AppStatus.Contains("Rejected"))).Select(reqInfo => new RequestInformation
{
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus,
RequestApps = reqInfo.RequestApps
.Where(a => a.AppProvisioningCompleteTime != null)
.Where(b => b.AppTeamCompleteTime == null)
.Where(x => !x.AppStatus.Contains("Rejected"))
.Where(b => b.RequestAppDataChoices.Any(a => a.AppDataChoiceDl == groupName)).ToList()
});

EFCore 2.2 GroupBy Sum and DateDiff

I'm trying to translate the following SQL in to an EF Core query and I'm getting warnings that GroupBy and Sum will be evaluated locally. Is there anyway currently to write this that it will fully translate to SQL?
SELECT UserId, ST.StatusId, SUM(DATEDIFF(MINUTE, StartDate, ISNULL(EndDate,GETDATE()))) AS Time
FROM StatusTransaction ST
WHERE
TeamManagerId = 1
AND StartDate >= N'01-01-2019'
AND ISNULL(EndDate,GETDATE()) <= N'01-02-2019'
GROUP BY UserId, ST.StatusId
ORDER BY UserId
And these are the EF queries I've used:
var efFunction = await context
.Where(st => st.TeamManagerId == tmId && st.StartDate >= dateFrom && (st.EndDate ?? DateTime.Now) <= dateTo)
.GroupBy(st => new { st.UserId, st.StatusId })
.Select(g => new
{
g.Key.UserId,
g.Key.StatusId,
Time = g.Sum(st => Microsoft.EntityFrameworkCore.EF.Functions.DateDiffMinute(st.StartDate, st.EndDate)) // null check not done on end date - (st.EndDate ?? DateTime.Now) causes an error here
}).ToListAsync(cancellationToken).ConfigureAwait(false);
var simpleDateSubtraction = await context
.Where(st => st.TeamManagerId == tmId && st.StartDate >= dateFrom && (st.EndDate ?? DateTime.Now) <= dateTo)
.GroupBy(st => new { st.UserId, st.StatusId })
.Select(g => new
{
g.Key.UserId,
g.Key.StatusId,
Time = g.Sum(st => st.EndDate.Value.Subtract(st.StartDate).Minutes)// null check not done on end date - (st.EndDate ?? DateTime.Now) causes an error here
}).ToListAsync(cancellationToken).ConfigureAwait(false);
var groupBySimpleSum = await context
.Where(st => st.TeamManagerId == tmId)
.GroupBy(st => new { st.TeamManagerId, st.OperationsManagerId })
.Select(g => new
{
g.Key.OperationsManagerId,
g.Key.TeamManagerId,
Foo = g.Sum(st => st.UserId) // nonsense but a simple column to sum, this translates fully to SQL
}).ToListAsync(cancellationToken).ConfigureAwait(false);
First, EF Core still doesn't support translating TimeSpan operations, and DateTime difference produces TimeSpan, hence EF.Functions.DateDiff methods are the right way to go.
Second, it still can translate GroupBy aggregates only on simple member accessor expressions. So you have to either pre Select the GroupBy expressions:
var query = context
.Where(st => st.TeamManagerId == tmId
&& st.StartDate >= dateFrom
&& (st.EndDate ?? DateTime.Now) <= dateTo
)
.Select(st => new
{
st.UserId,
st.StatusId,
Time = EF.Functions.DateDiffMinute(st.StartDate, st.EndDate ?? DateTime.Now)
})
.GroupBy(st => new { st.UserId, st.StatusId })
.Select(g => new
{
g.Key.UserId,
g.Key.StatusId,
Time = g.Sum(st => st.Time)
});
or use the GroupBy overload which allows pre selecting the source for the aggregates:
var query = context
.Where(st => st.TeamManagerId == tmId
&& st.StartDate >= dateFrom
&& (st.EndDate ?? DateTime.Now) <= dateTo
)
.GroupBy(st => new { st.UserId, st.StatusId }, st => new
{
Time = EF.Functions.DateDiffMinute(st.StartDate, st.EndDate ?? DateTime.Now)
})
.Select(g => new
{
g.Key.UserId,
g.Key.StatusId,
Time = g.Sum(st => st.Time)
});

Reactive ToProperty not setting property

I have the property Sessions in my vm
private ObservableAsPropertyHelper<IEnumerable<SessionViewModel>> _Sessions;
public IEnumerable<SessionViewModel> Sessions
{
get { return _Sessions.Value; }
}
I am trying to set this in the constructor like so
this.WhenAny(x => x.LocationsViewModel.CurrentLocation, x => x.Date, (location, date) => location.Value)
.Where(x => x != null)
.Select(x => FilterSessions(x.Id, Date))
.ToProperty(this, x => x.Sessions);
FilterSessions looks like so
private IEnumerable<SessionViewModel> FilterSessions(Guid locationId, DateTime date)
{
return _allSessions
.Where(s => s.SessionLocationId == locationId && s.StartTime.Date == date.Date)
.Select(s => new SessionViewModel(s));
}
It returns 10 SessionViewModel's but _Sessions is never set.
What platform is this? Certain platforms do not allow setting private fields via reflection. Instead, you can just use the return value of ToProperty:
_Sessions = this.WhenAny(x => x.LocationsViewModel.CurrentLocation, x => x.Date, (location, date) => location.Value)
.Where(x => x != null)
.Select(x => FilterSessions(x.Id, Date))
.ToProperty(this, x => x.Sessions);
Or better, in RxUI 5.x:
this.WhenAny(x => x.LocationsViewModel.CurrentLocation, x => x.Date, (location, date) => location.Value)
.Where(x => x != null)
.Select(x => FilterSessions(x.Id, Date))
.ToProperty(this, x => x.Sessions, out _Sessions);
I worked around this by settings the property in the subscribe method like so:
this.WhenAny(x => x.LocationsViewModel.CurrentLocation, x => x.Date, (location, date) => location.Value)
.Where(x => x != null)
.Select(x => FilterSessions(x.Id, Date))
.Subscribe(x => Sessions = x);

Linq - How to exclude items from autocomplete array

I have the following code that gives me a an array in an autocomplete extender:
return autocomplete.tblAutoCompletes
.Where(p => p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText))
.OrderBy(p => p.ACItem)
.Select(p => p.ACItem)
.Take(count)
.ToArray();
However, I may need to programmatically exclude certain items from the array.
How would I do that? So for example, ACItem list = Product1, Product2, Product3.
How would I amend the code so that Product2 is excluded?
autocomplete.tblAutoCompletes
.Where(p => p.MemberId == memberid && p.LocationId == locationid && p.ACItem.Contains(prefixText))
.OrderBy(p => p.ACItem)
.Select(p => p.ACItem)
.Take(count)
.Where(p => p != Product1)
.Select(p => p)
.ToArray();

Resources