How to include two object inside the same select on Linq MVC5 - c#

I do have a complex query to select a full object called Performance
The Performance relationship with others objects is:
Performance has a list of Index
Index has a list of SubIndex
SubIndex has a list of Indicator
Indicator has a list of Item
Item relationship with Spot and Measurement:
Item has one Spot and one Measurement
The query below returns exactly what I want, but I would like to include the Spot and Measurement to the Item object.
return _context.Performance.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items))))
.SingleOrDefault(p => p.Id == id);
I have tried the query below and it is returning the Measurement object. How to include the Spot object?
return _context.Performance.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items.Select(tm => tm.Measurement)))))
.SingleOrDefault(p => p.Id == id);

You could add second Include too;
return _context.Performance.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items.Select(tm => tm.Measurement)))))
.Include(i => i.Indexes
.Select(s => s.SubIndexes
.Select(d => d.Indicators
.Select(t => t.Items.Select(tm => tm.Spot)))))
.SingleOrDefault(p => p.Id == id);

Related

Linq includes in nested group by query

I have a relatively complex query below with a few nested group by queries. The problem is that I don't know how I can add includes to any of the group by queries. Is there a way to include subproperties in the sub group queries in EF6?
return db.PatientOrders
.Include(x => x.Patient) // this has no effect
.Where(x => !x.ProcessedOn.HasValue && x.Patient.Home.PharmacyId == pharmacyID)
.GroupBy(x => x.Patient.Home)
.ToDictionary(x => x.Key, x => x
.ToList()
.GroupBy(y => y.Patient.Department)
.ToDictionary(y => y.Key, y => y
.Include(x => x.OrderLines) // this does not compile
.ToList()
.GroupBy(z => z.Patient)
.ToDictionary(z => z.Key, z => z.ToList(), new PatientEqualityComparer()), new HomeDepartmentEqualityComparer()), new HomeEqualityComparer());
I figured out a way to do it but I'm not sure if the solution is any good performance-wise.
// group by reshapes query so previous includes are lost
// solution: flatten after group by then do includes then group by again
return db.PatientOrders
.GroupBy(x => x.Patient.Home) // Group
.SelectMany(g => g.AsEnumerable()) // Ungroup
.Include(x => x.Patient)
.Include(x => x.Patient.Home)
.Include(x => x.Patient.Doctor)
.Include(x => x.Patient.Department)
.Include(x => x.OrderLines)
.Include(x => x.OrderLines.Select(y => y.Product))
.Where(x => !x.ProcessedOn.HasValue && x.Patient.Home.PharmacyId == pharmacyID)
.AsEnumerable() // Switch to LINQ to Objects
.GroupBy(x => x.Patient.Home) // Group again
.ToDictionary(x => x.Key, x => x
.ToList()
.GroupBy(y => y.Patient.Department)
.ToDictionary(y => y.Key, y => y
.ToList()
.GroupBy(z => z.Patient)
.ToDictionary(z => z.Key, z => z.ToList(), new PatientEqualityComparer()), new HomeDepartmentEqualityComparer()), new HomeEqualityComparer());

Compare Matching Element using single query in Iqueryable

I am trying to compare two List of UserGroup from two different Table using a single query ie, by not hitting DB multiple times.
currently I am fetching all assigned UserGroup in one query, and comparing with all allowed Usergroup in other query.
var query = _context.AppSubOperationUserGroupMappings.Where(filterPredicate)
.Select(x => x.UserGroup)
.ToList();
var allowedUserGroups = _context.Users.Where(x => x.Id == userId)
.Select(x => x.UserGroupUserMappings.Select(y => y.UserGroup))
.First()
.ToList();
return query.Any(a => allowedUserGroups.Any(b => b.Id == a.Id));
How can I merge them into single Query?
Remove ToList and First, use Join and SelectMany
var query = _context.AppSubOperationUserGroupMappings.Where(filterPredicate)
.Select(x => x.UserGroup);
var allowedUserGroups = _context.Users.Where(x => x.Id == userId)
.SelectMany(x => x.UserGroupUserMappings, (x, y) => y.UserGroup);
return query
.Join(
allowedUserGroups,
x => x.Id,
x => x.Id,
(x, y) => false) // doesn't matter what to select
.Any();

NHibernate and MySql Missing column Exception

From time to time my web application begins throwing the following errors.
Using NHibernate 4.0.0.4000 and MySql.Data 6.8.3
Stack Trace
ERROR [(null)] - Message:could not execute query
NHibernate log
NHibernate.Util.ADOExceptionReporter WARN - System.IndexOutOfRangeException: Could not find specified column in results:
Once once of these errors occur it begins to happen frequently until the web application is restart.
It's odd that it only happens to some users and not all. Also I noticed in this particular log message the values of p4 and p5 should be swapped.
Is this an issue with the query cache?
Does anyone have some insight into why this is happening?
If it helps here is the gnarly query (but I see this error on much simpler queries as well)
FunderInfoViewModel funderDto = null;
Funder funderAlias = null;
Contact contactAlias = null;
var totalOpportunitiesAwardedCount = QueryOver.Of<Opportunity>()
.Where(o => o.Funder.Id == funderAlias.Id)
.And(o => o.Status == OpportunityStatus.Awarded || o.Status == OpportunityStatus.AwardedClosed)
.SelectList(list => list
.SelectCount(o => o.Id));
var totalOpportunitiesAwardedSum = QueryOver.Of<Opportunity>()
.Where(o => o.Funder.Id == funderAlias.Id)
.And(o => o.Status == OpportunityStatus.Awarded || o.Status == OpportunityStatus.AwardedClosed)
.SelectList(list => list
.SelectSum(o => o.AmountAwarded));
var totalOpportunitiesCount = QueryOver.Of<Opportunity>()
.Where(o => o.Funder.Id == funderAlias.Id)
.SelectList(list => list
.SelectCount(o => o.Id));
IEnumerable<FunderInfoViewModel> funders = _session.QueryOver(() => funderAlias)
.Left.JoinAlias(f => f.Contacts, () => contactAlias, x => x.IsDefault)
.Where(o => o.Organization.Id == organizationId)
.SelectList(list => list
.Select(x => x.Id)
.WithAlias(() => funderDto.Id)
.Select(x => x.Name)
.WithAlias(() => funderDto.Name)
.Select(x => x.Description)
.WithAlias(() => funderDto.Description)
.Select(x => x.AreasOfInterest)
.WithAlias(() => funderDto.AreasOfInterest)
.Select(x => x.Type)
.WithAlias(() => funderDto.FunderType)
.Select(x => x.TaxId)
.WithAlias(() => funderDto.TaxId)
.Select(x => x.PhoneNumber)
.WithAlias(() => funderDto.PhoneNumber)
.Select(x => x.FaxNumber)
.WithAlias(() => funderDto.FaxNumber)
.Select(x => x.EmailAddress)
.WithAlias(() => funderDto.EmailAddress)
.Select(x => x.Website)
.WithAlias(() => funderDto.Website)
.Select(x => x.CustomLink)
.WithAlias(() => funderDto.CustomLink)
.Select(x => x.MinimumFundingRange)
.WithAlias(() => funderDto.MinimumFundingRange)
.Select(x => x.MaximumFundingRange)
.WithAlias(() => funderDto.MaximumFundingRange)
.Select(() => contactAlias.FirstName)
.WithAlias(() => funderDto.PrimaryContactFirstName)
.Select(() => contactAlias.LastName)
.WithAlias(() => funderDto.PrimaryContactLastName)
.Select(() => contactAlias.Title)
.WithAlias(() => funderDto.PrimaryContactTitle)
.SelectSubQuery(totalOpportunitiesAwardedCount)
.WithAlias(() => funderDto.AwardedOpportunitiesCount)
.SelectSubQuery(totalOpportunitiesAwardedSum)
.WithAlias(() => funderDto.AwardedOpportunitiesValue)
.SelectSubQuery(totalOpportunitiesCount)
.WithAlias(() => funderDto.OpportunitiesCount)
)
.OrderBy(f => f.Name)
.Asc
.TransformUsing(Transformers.AliasToBean<FunderInfoViewModel>())
.List<FunderInfoViewModel>();
Ok got the problem. Its because some of the arguement you are passing in your prepared statement is null, thats why this error. I had similar issue earlier and i solved it by checking only if it is not null add it in query filtering.
Also there is another possibility of row lock by any other query. Are you using lock in mysql query?
2nd problem seems like see the solution stated below
https://forums.asp.net/t/1230295.aspx?IDataReader+Could+not+find+specified+column+in+results+

EF6 Condition based on sub child

I have this C# code that works, but I'd like to be able to choose the Agency if a person is in it all in the query. Is there a way to do that all in the query?
var retVal = new List<Agency>();
var items=_db.Agencies
.Include(x => x.AgencyMembers.Select(y => y.Person))
.Where(w => w.NationId == User.NationId).ToList();
foreach (var agency in items)
{
if(agency.AgencyMembers.Any(c=>c.Person.Id==personId))
retVal.Add(agency);
}
return retVal;
You should be able to just add that predicate to your query.
return _db.Agencies
.Include(x => x.AgencyMembers.Select(y => y.Person))
.Where(w => w.NationId == User.NationId)
.Where(agency => agency.AgencyMembers.Any(c=>c.Person.Id==personId))
.ToList();
Depending what navigation properties you have, you may be able to simplify it by starting from the person.
return _db.People
.Single(p => p.Id == personId)
.Agencies
.Where(w => w.NationId == User.NationId)
.ToList();
You can try this:
var items=_db.Agencies
.Include(x => x.AgencyMembers.Select(y => y.Person))
.Where(agency=> agency.NationId == User.NationId && agency.AgencyMembers.Any(c=>c.Person.Id==personId))
.ToList();

NHibernate QueryOver and string.format

I am working with QueryOver in NHibernate and I want to customize one property of my projected DTO using the following syntax:
IEnumerable<PersonResponseMessage> persons =
session.QueryOver<PersonEntity>()
.SelectList(list => list
.Select(p => p.Active).WithAlias(() => dto.Active)
.Select(p => p.Alert).WithAlias(() => dto.Alert)
.Select(p => p.Comments).WithAlias(() => dto.Comments)
.Select(p => string.Format("{0}api/Person/{1}", uriHelper.Root, p.Id)).WithAlias(() => dto.DetailsUrl)
)
.TransformUsing(Transformers.AliasToBean<PersonResponseMessage>())
.List<PersonResponseMessage>();
Unfortunately NHibernate cannot do this and throws an exception saying that:
Variable P referenced from scope "" is not defined
There are in common two ways. Partially we can move that concat operation on the DB side, as documented here:
16.7. Projection Functions
In this case, we'll use the Projections.Concat:
.SelectList(list => list
.Select(p => p.Active).WithAlias(() => dto.Active)
.Select(p => p.Alert).WithAlias(() => dto.Alert)
.Select(p => p.Comments).WithAlias(() => dto.Comments)
// instead of this
//.Select(p => string.Format("{0}api/Person/{1}", uriHelper.Root, p.Id))
// .WithAlias(() => dto.DetailsUrl)
// use this
.Select(p => Projections.Concat(uriHelper.Root, Projections.Concat, p.Id))
.WithAlias(() => dto.DetailsUrl)
)
.TransformUsing(Transformers.AliasToBean<PersonResponseMessage>())
.List<PersonResponseMessage>();
But I would vote for ex-post processing on the Application tier, in C#:
.SelectList(list => list
.Select(p => p.Active).WithAlias(() => dto.Active)
.Select(p => p.Alert).WithAlias(() => dto.Alert)
.Select(p => p.Comments).WithAlias(() => dto.Comments)
// just the ID
.Select(p => p.Id).WithAlias(() => dto.Id)
)
.TransformUsing(Transformers.AliasToBean<PersonResponseMessage>())
.List<PersonResponseMessage>()
// do the concat here, once the data are transformed and in memory
.Select(result =>
{
result.DetailsUrl = string.Format("{0}api/Person/{1}", uriHelper.Root, p.Id)
return result;
});

Categories