SQL query takes too long to execute. Need to improve performance of query - sql

I'm using SQL Server, .NET 5 environment. This SQL query takes too long to execute. This query waiting time is almost 3 min but there are only 35 records. Are there better way to optimize this query ?
var allmeetings = await _context.MeetingMaster
.Where(x => x.IsActive == true &&
(x.MeetingParticipants.Any(y => y.ParticipantId == Convert.ToInt32(_currentUserService.CurrentUserId)) ||
x.OrganizedById == Convert.ToInt32(_currentUserService.CurrentUserId)))
.Include(a => a.MeetingParticipants)
.ThenInclude(b => b.Participant)
.Include(a => a.MeetingAgendaItems)
.ThenInclude(e => e.MeetingActionItems)
.ThenInclude(w => w.ActionItemLogs)
.Include(a => a.MeetingAgendaItems)
.ThenInclude(e => e.MeetingActionItems)
.ThenInclude(w => w.ActionItemResposibilities)
.Include(g => g.MeetingAgendaItems)
.ThenInclude(v => v.MeetingAgendaItemTypes)
.ThenInclude(j => j.AgendaItemRef)
.Include(w => w.MeetingAgendaItems)
.ThenInclude(d => d.RestrictedAgendaItemList)
.ThenInclude(s => s.ParticipantRef)
.Include(s => s.MeetingAgendaItems)
.ThenInclude(q => q.MeetingAgendaItemSupportiveDocuments)
.Include(c => c.MonthsRef)
.Include(z => z.YearsRef)
.Include(g => g.MeetingMinutesDoc)
.Include(c => c.Project)
.Include(c => c.Category)
.Include(l => l.MeetingSuggestions)
.Include(q => q.MeetingMattersArises)
.ThenInclude(i => i.MattersAriseResponsibilities)
.ThenInclude(s => s.ResponsiblePerson)
.Include(e => e.MeetingMattersArises)
.ThenInclude(w => w.MattersAriseReviewerComments)
.Include(s => s.MeetingMattersArises)
.ThenInclude(e => e.MattersAriseLogs)
.AsSplitQuery()
.ToListAsync(cancellationToken);
var result = allmeetings.Where(x => x.IsActive == true &&
x.isRecurringMeeting == false &&
(x.MeetingParticipants.Any(y => y.ParticipantId == Convert.ToInt32(_currentUserService.CurrentUserId)) || x.OrganizedById == Convert.ToInt32(_currentUserService.CurrentUserId))).ToList();
var RecMeetings = allmeetings.Where(x => x.IsActive == true &&
x.isRecurringMeeting == true &&
(x.MeetingParticipants.Any(y => y.ParticipantId == Convert.ToInt32(_currentUserService.CurrentUserId)) || x.OrganizedById == Convert.ToInt32(_currentUserService.CurrentUserId))).ToList();
var groupedRecMeetings = RecMeetings.GroupBy(u => u.MeetingRefId.Substring(0, u.MeetingRefId.LastIndexOf('-'))).Select(grp => grp.ToList()).ToList();
var GraeterMeetings = new List<MeetingMaster>();
foreach (var met in groupedRecMeetings)
{
result.AddRange(met.FindAll(x => x.MeetingStatus != "Initiated" ));
GraeterMeetings.AddRange(met.FindAll(x => x.MeetingStatus == "Initiated"));
if(GraeterMeetings.Count != 0)
{
result.Add(GraeterMeetings.OrderBy(x => x.MeetingDate).First());
}
GraeterMeetings.Clear();
}
return result.OrderByDescending(d => d.Id).ToList();

First of all you have so many Includes() and ThenIncludes(), this if really bad for your performance. Is there a way by any chance you can reduce these includes -> only use the necessary one's.
Then i would that you execute the .ToList() query at the end of the statement (befor your return)
Down below is an example how i've done it in the past (with pagination & filtration):
var context = _context.People
.Include(x => x.Parents)
.ThenInclude(x => x.Adress)
.Include(x => x.Job)
.Include(x => x.Hobbies);
var items = string.IsNullOrWhiteSpace(query)
? context
: context.Where(x => x.Name.Contains(query));
var filters = new List<int>();
if (filter != null)
{
filters = filter.Split(',').Select(int.Parse).ToList();
items = items.Where(x => x.Parents.Select(s => s.AdressId).Any(z => filters.Any(y => y == z)));
}
return await items.Skip(page * take).Take(take).ToListAsync();

Related

Joining tables in NHibernate

I have a query below, How can recreate this one to join the tables that will return a list of SurveyProjectNormDTO using NHibernate? Any help please?
using (var session = OpenSession()){
var projectGroupIds = session.Query<ReportingStructureNodeProjectGroups>()
.Where(x => x.NodeID == nodeId);
projectGroupIds.Fetch(x => x.ProjectGroupID).ToFuture();
var projectIds = session.Query<ProjectGroup>().Where(p => projectGroupIds.Contains(p.Id));
projectIds.Fetch(x => x.ProjectID).ToFuture();
var projectNormProjects = session.Query<SurveyProjectNorm>().Where(x => projectIds.Contains(x.SurveyProjectId));
projectNormProjects.Fetch(x => x.ShortLabels).ToFuture();
projectNormProjects.Fetch(x => x.ReportingNames).ToFuture();
projectNormProjects.Fetch(x => x.NormProject).ToFuture();
var response = new List<SurveyProjectNormDTO>();
projectNormProjects.ToList().ForEach(
p =>
{
response.Add(
new SurveyProjectNormDTO { Id = p.Id, ProjectName = p.NormProject.ProjectName, ReportingName = p.ReportingNames.Select(s => s.LocalizedText).FirstOrDefault() });
});
return response;
I am not sure if these let commands will work fine but you can try this. It will do a single hit on the database fetching the properties. Test it and let us know if it works.
var queryResult = (from p in session.Query<SurveyProjectNorm>()
let projectGroupIds = session.Query<ReportingStructureNodeProjectGroups>().Where(x => x.NodeID == nodeId).Select(x => x.Id)
let projectIds = session.Query<ProjectGroup>().Where(x => projectGroupIds.Contains(x.Id)).Select(x => x.Id)
where projectIds.Contains(p.SurveyProjectId)
select p)
.Fetch(x => x.ShortLabels)
.Fetch(x => x.ReportingNames)
.Fetch(x => x.NormProject)
.ToList();
var response = new List<SurveyProjectNormDTO>();
queryResult.ForEach(p =>
response.Add(new SurveyProjectNormDTO {
Id = p.Id,
ProjectName = p.NormProject.ProjectName,
ReportingName = p.ReportingNames.Select(s => s.LocalizedText).FirstOrDefault() }));
return result;

NHibernate projection: How to create AliasToBean projection?

I am trying to convert this inefficient query into one that projects into a dto.
Original query looks like this:
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(x => x.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(x => x.ClientPolicy, () => clientPolicyAlias)
.Where(y => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.List()
.Select(x => new FlatChargeAccessFeeInfo()
{
FlatChargeAccessFeeId = x.Id,
ClientName = x.ClientPolicy.Bid.Client.Name,
PolicyNumber = x.ClientPolicy.PolicyNumber,
ClientPolicyId = x.ClientPolicy.Id,
AgreementAccessFeeId = x.AgreementAccessFee.Id,
ShouldCheckBeGenerated = x.ShouldCheckBeGenerated,
MonthlyFee = x.MontlyFeeAmount.Amount.ToString(),
PolicyYear = x.ClientPolicy.PolicyNumber.Year
})
.ToList();
I tried it like this:
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(x => x.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(x => x.ClientPolicy, () => clientPolicyAlias)
.Where(y => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => feeInfo.FlatChargeAccessFeeId)
.Select(x => x.ClientPolicy.Bid.Client.Name).WithAlias(() => feeInfo.ClientName)
.Select(x => x.ClientPolicy.PolicyNumber).WithAlias(() => feeInfo.PolicyNumber)
.Select(x => x.ClientPolicy.Id).WithAlias(() => feeInfo.ClientPolicyId)
.Select(x => x.AgreementAccessFee.Id).WithAlias(() => feeInfo.AgreementAccessFeeId)
.Select(x => x.ShouldCheckBeGenerated).WithAlias(() => feeInfo.ShouldCheckBeGenerated)
.Select(x => x.MontlyFeeAmount.Amount.ToString()).WithAlias(() => feeInfo.MonthlyFee)
.Select(x => x.ClientPolicy.PolicyNumber.Year).WithAlias(() => feeInfo.PolicyYear)
)
.TransformUsing(Transformers.AliasToBean<FlatChargeAccessFeeInfo>())
.List<FlatChargeAccessFeeInfo>();
and I am getting an error that variable "x" has been referenced in scope but was not defined. What is the proper syntax to convert this?
After help from Andrew, here is the correct version that works
ClientPolicy clientPolicyAlias = null;
Client clientAlias = null;
Bid bidAlias = null;
AgreementAccessFee agreementAccessFeeAlias = null;
FlatChargeAccessFee flatChargeAccessFeeAlias = null;
FlatChargeAccessFeeInfo feeInfo = null;
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(a => a.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(b => b.ClientPolicy, () => clientPolicyAlias)
.JoinAlias(b=>b.Bid,()=>bidAlias)
.JoinAlias(b=>b.Client, ()=>clientAlias)
.Where(c => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.SelectList(list => list
.Select(d => d.Id).WithAlias(() => feeInfo.FlatChargeAccessFeeId)
.Select(e => clientAlias.Name).WithAlias(() => feeInfo.ClientName)
.Select(e => clientAlias.Number).WithAlias(() => feeInfo.ClientNumber)
.Select(f => bidAlias.OptionNumber).WithAlias(() => feeInfo.BidOptionNumber)
.Select(f => bidAlias.Year).WithAlias(()=>feeInfo.PolicyYear)
.Select(g => clientPolicyAlias.Id).WithAlias(() => feeInfo.ClientPolicyId)
.Select(h => agreementAccessFeeAlias.Id).WithAlias(() => feeInfo.AgreementAccessFeeId)
.Select(j => j.ShouldCheckBeGenerated).WithAlias(() => feeInfo.ShouldCheckBeGenerated)
.Select(k => k.MontlyFeeAmount.Amount).WithAlias(()=>feeInfo.MonthlyFee)
)
.TransformUsing(Transformers.AliasToBean<FlatChargeAccessFeeInfo>())
.List<FlatChargeAccessFeeInfo>();
You're close, a few things though:
This select:
.Select(x => x.MontlyFeeAmount.Amount.ToString()).WithAlias(() => feeInfo.MonthlyFee)
will not work. QueryOver attempts to turn your code directly into SQL. If the property does not exist as a column in the database, the query won't work properly (unless you're using a mapped custom type, QueryOver can handle those)
Nested property access won't work either:
.Select(x => x.ClientPolicy.Bid.Client.Name).WithAlias(() => feeInfo.ClientName)
for a similar reason listed above. QueryOver will attempt to turn your property access directly into SQL. You'll need to explicitly join from ClientPolicy to Bid to Client.
In general, remember that you're writing code that's going to be turned into SQL. In fact, I normally write the SQL I want to generate first and then write the QueryOver that corresponds to that. Hope that helps!

fluent hibernate Transformers.AliasToBean is not working as expected

I have three tables. One is the master table: TableA. One table is referenced by TableA called ReferencedTable and lastly a lookup table referenced by ReferencedTable.
I have this query that returns the ten most recent objects as:
TableADTO TableAlias = null;
LookupTableDTO LookupTableAlias = null;
ReferencedDTO ReferencedAlias = null;
dtos = session.QueryOver(() => TableAlias)
.JoinAlias(() => TableAlias.Object, () =>ReferencedAlias)
.JoinAlias(() => ReferencedAlias.ObjectType, () => LookupTableAlias)
.Where(() => ReferencedAlias.PersonId == user.Id &&
(LookupTableAlias.Id != INVOICE_ID ||
LookupTableAlias.Id != FINANCIAL_ID) &&
TableAlias.Status == NEW_STATUS_FLAG &&
ReferencedAlias.ReceivedDate < DateTime.Now)
.Take(10)
.List()
.Select(dto=>
new AbreviatedDTO
{
Id = dto.Referenced.Id,
Field1 = dto.Field1,
Priority = dto.Referenced.Priority,
ReceivedDate = dto.Referenced.ReceivedDate,
Field1 = dto.Referenced.Field1,
Type = dto.Referenced.Lookup.TypeCode,
Status = dto.Status
}).ToList();
This works as expected. However, I thought the the transformation below would work too. It does bring 10 objects but the objects have all default values and are not populated (e.g. AbreviatedDTO.ReceivedDate = DateTime.Minimum). Am I doing something wrong with the QueryOver?
Any help would be appreciated.
Bill N
TableDTO TableAlias = null;
LookupTableDTO LookupTableAlias = null;
ReferencedDTO ReferencedAlias = null;
dtos = session.QueryOver(() => TableAlias)
.JoinAlias(() => TableAlias.Object, () =>ReferencedAlias)
.JoinAlias(() => ReferencedAlias.ObjectType, () => LookupTableAlias)
.Where(() => ReferencedAlias.PersonId == user.Id &&
(LookupTableAlias.Id != INVOICE_ID ||
LookupTableAlias.Id != FINANCIAL_ID) &&
TableAlias.Status == NEW_STATUS_FLAG &&
ReferencedAlias.ReceivedDate < DateTime.Now)
.SelectList(list => list
.Select(x => TableAlias.Field1)
.Select(x => ReferencedAlias.Id)
.Select(x => ReferencedAlias.Field1)
.Select(x => ReferencedAlias.ReceivedDate)
.Select(x => ReferencedAlias.Priority)
.Select(x => LookupTableAlias.TypeCode))
.TransformUsing(Transformers.AliasToBean<AbreviatedDTO>())
.Take(10)
.List<AbreviatedDTO>()
you'll need to define an alias for each selected field same as the propertyname in the resulting dto
AbreviatedDTO alias = null;
// in query
.SelectList(list => list
.Select(() => TableAlias.Field1).WithAlias(() => alias.Field1)

NHibernate fetch with transformation

im trying to query using QueryOver and im trying to do some transformation with fetching.
But im hitting error
HSPTransactionDto hspTransactionDto = null;
var hspTransactionDtoList =
Session.QueryOver<Transaction>()
.Where(x => x.TransactionStatus == TransactionStatus.Draft)
.Fetch(x => x.HealthServiceProvider).Eager
.Fetch(x => x.HealthMaintenanceOrganization).Eager
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => hspTransactionDto.Id)
.Select(x => x.Version).WithAlias(() => hspTransactionDto.Version)
.Select(x => x.HealthServiceProvider.Id).WithAlias(() => hspTransactionDto.HSPId)
.Select(x => x.HealthServiceProvider.Name).WithAlias(() => hspTransactionDto.HSPName)
.Select(x => x.HealthMaintenanceOrganization.Id).WithAlias(() => hspTransactionDto.HMOId)
.Select(x => x.HealthMaintenanceOrganization.Name).WithAlias(() => hspTransactionDto.HMOName)
.Select(x => x.HSPPatientCode).WithAlias(() => hspTransactionDto.HSPPatientCode)
.Select(x => x.PatientFirstName).WithAlias(() => hspTransactionDto.PatientFirstName)
.Select(x => x.PatientMiddleName).WithAlias(() => hspTransactionDto.PatientMiddleName)
.Select(x => x.PatientLastName).WithAlias(() => hspTransactionDto.PatientLastName)
)
.TransformUsing(Transformers.AliasToBean<HSPTransactionDto>()).List<HSPTransactionDto>();
return hspTransactionDtoList;
anyone can help?
actually found the answer just need to put some alias so i ended up with
HSPTransactionDto hspTransactionDto = null;
HealthMaintenanceOrganization hmoAlias = null;
HealthServiceProvider hspAlias = null;
var hspTransactionDtoList =
Session.QueryOver<Transaction>()
.Where(a => a.TransactionStatus == TransactionStatus.Draft)
.Fetch(b => b.HealthServiceProvider).Eager
.Fetch(c => c.HealthMaintenanceOrganization).Eager
.JoinAlias(x=> x.HealthMaintenanceOrganization,() => hmoAlias)
.JoinAlias(x => x.HealthServiceProvider, () => hspAlias)
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => hspTransactionDto.Id)
.Select(x => x.Version).WithAlias(() => hspTransactionDto.Version)
.Select(x => hspAlias.Id).WithAlias(() => hspTransactionDto.HSPId)
.Select(x => hspAlias.Name).WithAlias(() => hspTransactionDto.HSPName)
.Select(x => hmoAlias.Id).WithAlias(() => hspTransactionDto.HMOId)
.Select(x => hmoAlias.Name).WithAlias(() => hspTransactionDto.HMOName)
.Select(x => x.HSPPatientCode).WithAlias(() => hspTransactionDto.HSPPatientCode)
.Select(x => x.PatientFirstName).WithAlias(() => hspTransactionDto.PatientFirstName)
.Select(x => x.PatientMiddleName).WithAlias(() => hspTransactionDto.PatientMiddleName)
.Select(x => x.PatientLastName).WithAlias(() => hspTransactionDto.PatientLastName)
)
.TransformUsing(Transformers.AliasToBean<HSPTransactionDto>()).List<HSPTransactionDto>();
return hspTransactionDtoList;
anyone know a cleaner way?
I think you don't need to use Fetch, because you've used Select for selective properties and it's grouped with DTO:
HSPTransactionDto hspTransactionDto = null;
HealthMaintenanceOrganization hmoAlias = null;
HealthServiceProvider hspAlias = null;
var hspTransactionDtoList =
Session.QueryOver<Transaction>()
.Where(a => a.TransactionStatus == TransactionStatus.Draft)
.JoinAlias(x=> x.HealthMaintenanceOrganization,() => hmoAlias)
.JoinAlias(x => x.HealthServiceProvider, () => hspAlias)
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => hspTransactionDto.Id)
.Select(x => x.Version).WithAlias(() => hspTransactionDto.Version)
.Select(x => hspAlias.Id).WithAlias(() => hspTransactionDto.HSPId)
.Select(x => hspAlias.Name).WithAlias(() => hspTransactionDto.HSPName)
.Select(x => hmoAlias.Id).WithAlias(() => hspTransactionDto.HMOId)
.Select(x => hmoAlias.Name).WithAlias(() => hspTransactionDto.HMOName)
.Select(x => x.HSPPatientCode).WithAlias(() => hspTransactionDto.HSPPatientCode)
.Select(x => x.PatientFirstName).WithAlias(() => hspTransactionDto.PatientFirstName)
.Select(x => x.PatientMiddleName).WithAlias(() => hspTransactionDto.PatientMiddleName)
.Select(x => x.PatientLastName).WithAlias(() => hspTransactionDto.PatientLastName)
)
.TransformUsing(Transformers.AliasToBean<HSPTransactionDto>()).List<HSPTransactionDto>();
return hspTransactionDtoList;

NHIBERNATE QUERYOVER

Hi
How to use queryover (Join) for same table...example
if (!string.IsNullOrEmpty(ufResidencia))
{
EnderecoProspect endProspectRes =null;
TipoEndereco tipoEndProspectRes = null;
query
.JoinQueryOver<EnderecoProspect>(x => x.Enderecos, () => endProspectRes)
.And(() => endProspectRes.Uf == ufResidencia)
.JoinQueryOver<TipoEndereco>(x => x.TipoEndereco, () => tipoEndProspectRes)
.And(() => tipoEndProspectRes.Descricao != "Fazenda");
}
if (!string.IsNullOrEmpty(ufFazenda))
{
EnderecoProspect endProspectFaz = null;
TipoEndereco tipoEndProspectFaz = null;
query
.JoinQueryOver<EnderecoProspect>(x => x.Enderecos, () => endProspectFaz)
.And(() => endProspectFaz.Uf == ufFazenda)
.JoinQueryOver<TipoEndereco>(x => x.TipoEndereco, () => tipoEndProspectFaz)
.And(() => tipoEndProspectFaz.Descricao == "Fazenda");
}
When I try to run I get the message that the path is duplicated.
Try using an alias
EnderecoProspect additionalProspect = null;
query
.JoinQueryOver<EndercoProspect>(x => x.Endercos, () => additionalProspect)...