I got the following error message from nhibernate:
{"not an association: ID"}
Model.Order orderAlias = null;
Model.Unit unitAlias = null;
query to reproduce:
var query = m_hibernateSession.QueryOver<Model.Order>(() => orderAlias)
.JoinAlias(() => orderAlias.ID, () => unitAlias, JoinType.InnerJoin)
.TransformUsing(Transformers.DistinctRootEntity)
.OrderBy(x => x.PONumber).Desc.Take(5);
(for DB model look also here: nhibernate criteria for selecting from different tables)
What does this mean and how can I correctly retrieve my result list?
Thx
In Model.Order class, ID should be of type Model.Unit.
Make sure you have classes for both Model.Order and Model.Unit
Related
I have the following query in my application:
var Company = Db.Company.SingleOrDefault(si => si.Guid == companyId);
var items = Db.Programs.Where(w => w.SubCompanyId == Company.CompanyId)
.GroupBy(g => g.Projects).Include(i => i.Key.ProjectLeader);
if (skip.HasValue && take.HasValue)
{
items = items.OrderByDescending(o => o.Key.DatumAanmaak).Skip(skip.Value).Take(take.Value);
}
var materialized = items.ToList();
return materialized.Select(s => new Models.Project()
{
Guid = s.Key.Guid,
ProjectId = s.Key.Id,
Title = s.Key.Titel,
CompanyId= s.Key.CompanyId,
ProjectLeaderFk = s.Key.ProjectLeaderId,
ProjectLeaderName = s.Key.ProjectLeader.FullName,
IsIncoming = s.Key.IsIncoming ?? true,
ProgramCount = s.Count(w => w.TargetCompanyId == Company.CompanyId),
ApplicationAmount = s.Where(w => w.TargetCompanyId == Company.CompanyId).Sum(su => su.ApplicationAmount ),
AvailableAmount = s.Where(w => w.TargetCompanyId == Company.CompanyId).Sum(su => su.AvailableAmount)
}).ToList();
Since my project is code first, this gives the following error:
System.InvalidOperationException: 'Error generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning: An attempt was made to lazy-load navigation property 'ProjectLeider' on detached entity of type 'ProjectProxy'. Lazy-loading is not supported for detached entities or entities that are loaded with 'AsNoTracking()'.'. This exception can be suppressed or logged by passing event ID 'CoreEventId.DetachedLazyLoadingWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.'
What is exactly causing this error? I am not using AsNoTracking and I included that table that is causing the error in the query. What is the easiest way to solve this?
What is exactly causing this error? I am not using AsNoTracking and I included that table that is causing the error in the query.
Your query is falling into Ignored Includes category:
If you change the query so that it no longer returns instances of the entity type that the query began with, then the include operators are ignored.
The GroupBy operator is changing the entity type the query began with (Program) to something else, so .Include(i => i.Key.ProjectLeader) has no effect (is ignored).
Probably the easiest way to resolve it is to remove the materialization and project (Select) directly from the source queryable (items), e.g.
//var materialized = items.ToList();
return items.Select(s => new Models.Project() { ... }).ToList();
The following solved it for me: (using ThenInclude instead of Include)
var items = Dbc.SubSubsidieProgrammas.Include(i => i.Project).ThenInclude(i => i.ProjectLeider).Where(w => w.TargetCompanyId == bedrijf.BedrijfPk).GroupBy(g => g.Project);
I've got a table
Application
ApplicationID,
NAme
ApplicationSteps
AplicationStepID,
AplicationID,
StepID
ApplicationStepCriterias
ApplicationStepID,
CriteriaID
So I've got one SelectedCriteriaID - a user choose from a dropdown one criteria and he wants all the applications which has this SelectedCriteriaID in the table ApplicationStepCriterias
I tried
var ds = context.Applications
.Where(a => a.ApplicationSteps
.Select(x=>x.ApplicationStepCriterias
.Select(t=>t.CriteriaId))
.Contains(SelectesdCriteria));
But as I have as result IEnumerable<IEnumerable<int>> I cannot use Contains
Just I get a list of all the CriteriaIds for each ApplicationStep(also a sequence). Just I cannot think of way to get in one list all the CriteriIds.
First, let me try to get the names right. This is not a pure many-to-many association, because the junction class is part of the class model. It is what I unofficially call a 1-n-1 association. So you have
Application -< ApplicationSteps >- ApplicationStepCriterias
I'd strongly recommend to use singular names for your classes ...
Application -< ApplicationStep >- ApplicationStepCriterion
... so you can use plural for collection property names without getting confused.
If I'm right so far, you query should be
context.Applications
.Where(a => a.ApplicationSteps
.Any(x => selectedCriteria
.Contains(x.ApplicationStepCriterion.CriteriaId));
(and I'd also prefer CriterionId, probably referring to a Criterion class)
You may try something like this:
var applicationStepIds = context.ApplicationStepCriterias
.Where(i => i.CriteriaID == selectedCriteria)
.Select(i => i.ApplicationStepID)
.Distinct();
var applicationIds = context.ApplicationSteps
.Where(i => applicationStepIds.Contains(i.AplicationStepID))
.Select(i => i.AplicationID)
.Distinct();
var result = context.Applications.Where(i => applicationIds.Contains(i.ApplicationId));
I'm trying to group Reports by Type and return the most recent Created date for each Report Type, using LINQ to Entities. I did my research and read lots of questions and most of them are solved using a similar query than mine:
var query = ctx.DataWorkspace.ApplicationData.Reports
.GroupBy(i => i.ReportType)
.Select(i => new { name = i.Key, y = i.Max(h => h.DateCreated) });
But I get this error:
A query cannot return non-Entity types that contain embedded entities
What am I doing wrong? Is it because it's LINQ-to-Entities?
Error message is quite descriptive. Your anonymous type contains a property which is typed as an entity (name = i.Key part). You can't do that, because LINQ to Entities would not be able to track changes to these entities.
You can take just some of the properties from ReportType instead of entire entity:
var query = ctx.DataWorkspace.ApplicationData.Reports
.GroupBy(i => i.ReportType)
.Select(i => new { name = i.Key.Name, y = i.Max(h => h.DateCreated) });
i.Key.Name is just an example. Your entity probably has different property/properties you care about.
i want to build a query that will select some columns from a joined table (many to one relationship in my data model).
var q = ses.QueryOver<Task>().Select(x => x.Id, x => x.CreatedDate, x => x.AssigneeGroup.Name, x => x.AssigneeGroup.IsProcessGroup);
Here i'm retrieving properties from AssigneeGroup which is a reference to another table, specified in my mapping. But when I try to run this query I get
Exception: could not resolve property: AssigneeGroup.Name of: Task
So it looks like NHibernate is not able to follow relations defined in my mapping and doesn't know that in order to resolve AssigneeGroup.Name we should do a join from 'Task' to 'Groups' table and retrieve Group.Name column.
So, my question is, how to build such queries? I have this expression: x => x.AssigneeGroup.Name, how to convert it to proper Criteria, Projections and Aliases? Or is there a way to do this automatically? It should be possible because NHibernate has all the information...
Your query need association and should look like this:
// firstly we need to get an alias for "AssigneeGroup", to be used later
AssigneeGroup assigneeGroup = null;
var q = ses
.QueryOver<Task>()
// now we will join the alias
.JoinAlias(x => x.AssigneeGroup, () => assigneeGroup)
.Select(x => x.Id
, x => x.CreatedDate
// instead of these
// , x => x.AssigneeGroup.Name
// , x => x.AssigneeGroup.IsProcessGroup
// use alias for SELECT/projection (i.e. ignore "x", use assigneeGroup)
, x => assigneeGroup.Name
, x => assigneeGroup.IsProcessGroup
);
More and interesting reading:
NHibernate - CreateCriteria vs CreateAlias, to get more understanding when to use JoinAlias (CreateAlias) and when JoinQueryOver (CreateCriteria)
Criteria API for: 15.4. Associations
QueryOver API for 16.4. Associations
You have to join the two tables if you wish to select columns from something other than the root table/entity (Task in our case).
Here is an example:
IQueryOver<Cat,Kitten> catQuery =
session.QueryOver<Cat>()
.JoinQueryOver<Kitten>(c => c.Kittens)
.Where(k => k.Name == "Tiddles");
or
Cat catAlias = null;
Kitten kittenAlias = null;
IQueryOver<Cat,Cat> catQuery =
session.QueryOver<Cat>(() => catAlias)
.JoinAlias(() => catAlias.Kittens, () => kittenAlias)
.Where(() => catAlias.Age > 5)
.And(() => kittenAlias.Name == "Tiddles");
Alternatively you could use the nhibernate linq provider (nh > 3.0):
var q = ses.Query<Task>()
.Select(x => new
{
Id = x.Id,
CreatedDate = x.CreatedDate,
Name = x.AssigneeGroup.Name,
IsProcessGroup = x.AssigneeGroup.IsProcessGroup
});
Running this query:
var holderAccounts = db.AccountDetails.Include(p => p.BranchDetail)
.Where(p => holder.AccountDetails.Any(a => a.Id == p.Id));
I get this exception:
Unable to create a constant value of type 'CodeFirst.AccountDetail'. Only primitive types or enumeration types are supported in this context.
Relationships are:
AccountHolder 1 to many AccountDetail 1 to 1 BranchDetail
What am I doing wrong?
Try extracting the relevant Ids first:
var accountDetailIds = holder.AccountDetails.Select(a => a.Id);
var holderAccounts = db.AccountDetails
.Include(p => p.BranchDetail)
.Where(p => accountDetailIds.Contains(p.Id));
Most likely, Any() is not supported. Try this query:
var ids = holder.AccountDetails.Select(x => x.Id).ToList();
var holderAccounts = db.AccountDetails.Include(p => p.BranchDetail)
.Where(p => ids.Contains(p.Id));
I think what you are trying to do is the same as a SQL Where-In Clause. As Jeffery Khan mentioned, I would extract the criteria that you are going to query against and then perform the query in a separate statement. Hopefully this article will help you understand this good practice used to enhance the readability of the query.