The Person class has a association by Identity class (one-to-one) FirstName and LastName are a property of Person class also Sex and BirthDate are a property of Identity class.
I have a sql query as the following examples:
select FirstName,LastName,Identity.Sex,Identity.BirthDate from Person_Person as Person
inner join Person_Identity as Identity on Person.Id = Identity.Person_id_fk
WHERE FirstName like '%jack%' and LastName like '%smit%'
I convert it into QueyOver.
var q = SessionInstance.QueryOver<Person>();
if (!String.IsNullOrEmpty(searchPersonDto.FirstName)) //necessary
q = q.Where(p => p.FirstName.IsLike(searchPersonDto.FirstName, MatchMode.Anywhere));
if (!String.IsNullOrEmpty(searchPersonDto.LastName)) //necessary
q = q.Where(p => p.LastName.IsLike(searchPersonDto.LastName, MatchMode.Anywhere));
Person aliasPerson = null;
q = q.SelectList(list => list
.Select(p => p.Id).WithAlias(() => aliasPerson.Id)
.Select(p => p.FirstName).WithAlias(() => aliasPerson.FirstName)
.Select(p => p.LastName).WithAlias(() => aliasPerson.LastName)
.Select(p => p.Identity.Sex).WithAlias(() => aliasPerson.Identity.Sex)
.Select(p => p.Identity.BirthDate).WithAlias(() => aliasPerson.Identity.BirthDate))
.TransformUsing(Transformers.AliasToBean<Person>());
q.List<Person>();
But join in this query is not correct. It throw a exceotion by this message :
could not resolve property: Identity.Sex of: Domain.Entities.Person
How I should join Identity by Person?
Updated : Add the similar linq query
var q = SessionInstance.Query<Person>()
.Where(p => p.FirstName == searchPersonDto.FirstName)
.Select(p => new Person(p.Id)
{
FirstName = p.FirstName,
LastName = p.LastName,
Identity = new Identity()
{
Sex = p.PersonIdentity.Sex,
BirthDate = p.Identity.BirthDate
}
}).ToList<Person>();
I need to a query by QueryOver similar to above query by Linq.
Update2: not pretty but here goes
var results = q
.JoinAlias(p => p.Identity, () => identityAlias)
.SelectList(list => list
.Select(p => p.Id)
.Select(p => p.FirstName)
.Select(p => p.LastName)
.Select(p => identityAlias.Sex)
.Select(p => identityAlias.BirthDate)
.List<object[]>()
.Select(values => new Person((int)values[0])
{
FirstName = (string)values[1],
LastName = (string)values[2],
Identity = new Identity()
{
Sex = (string)values[3],
BirthDate = (DateTime)values[4],
}
})
.ToList<Person>();
Update: from your comments i would say, this is what you need.
code to fill a PersonDto
PersonDTO aliasDTO = null;
q = q
.JoinAlias(p => p.Identity, () => identityAlias)
.SelectList(list => list
.Select(p => p.Id).WithAlias(() => aliasDTO.Id)
.Select(p => p.FirstName).WithAlias(() => aliasDTO.FirstName)
.Select(p => p.LastName).WithAlias(() => aliasDTO.LastName)
.Select(p => identityAlias.Sex).WithAlias(() => aliasDTO.Sex)
.Select(p => identityAlias.BirthDate).WithAlias(() => aliasDTO.BirthDate))
.TransformUsing(Transformers.AliasToBean<PersonDTO>())
.List<PersonDTO>();
Orginal Answer:
q.JoinAlias(p => p.Identity, () => identityAlias)
// and later
.Select(p => identityAlias.Sex)
Update: in the code posted the AliasToBeanTransformer is not needed at all
var q = SessionInstance.QueryOver<Person>();
if (!String.IsNullOrEmpty(searchPersonDto.FirstName)) //necessary
q = q.Where(p => p.FirstName.IsLike(searchPersonDto.FirstName, MatchMode.Anywhere));
if (!String.IsNullOrEmpty(searchPersonDto.LastName)) //necessary
q = q.Where(p => p.LastName.IsLike(searchPersonDto.LastName, MatchMode.Anywhere));
var results = q.Fetch(p => p.Identity).Eager
.List<Person>();
Related
Since:
"Eager loading a collection navigation in a single query may cause
performance issues."
see: Source
And it is advise to use split queries with include. I wonder if instead of include in the query bellow:
var task = await context.Tasks
.Include(x => x.TaskDependencies)
.Select(x => new TaskBaseModel
{
Id = x.Id,
Name = x.Name,
Description = x.Description,
TaskDependencies= x.TaskDependencies.ToArray()
})
.SingleOrDefaultAsync(x => x.Id == _id);
I should do this:
var task = await context.Tasks
.Select(x => new TaskBaseModel
{
Id = x.Id,
Name = x.Name,
Description = x.Description,
TaskDependencies= context.TaskDependencies
.Where(y => y.TaskId == x.Id).ToArray()
})
.SingleOrDefaultAsync(x => x.Id == _id);
Anyone as any info regarding this? about performance, etc..
Regards
Both queries should have the same performance and SQL. Note that Include followed by Select is ignored by EF Core.
So, most comfortable query is:
var task = await context.Tasks
.Select(x => new TaskBaseModel
{
Id = x.Id,
Name = x.Name,
Description = x.Description,
TaskDependencies = x.TaskDependencies.ToArray()
})
.SingleOrDefaultAsync(x => x.Id == _id);
I have pretty simple LINQ expression
IQueryable<FreeBetDTO> records = UnitOfWork.FreeBets
.Include(f => f.FreeBetCategories)
.Include(f => f.FreeBetCards)
.Where(f => f.FreeBetCards.Any(cards => cards.UserId == request.UserId))
.Select(f => new FreeBetDTO
{
FreeBetId = f.FreeBetId
LineCategories = f.FreeBetCategories
.GroupBy(g => new { g.LineCategoryID, g.Title })
.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.Key.LineCategoryID,
Title = c.Key.Title
}).AsEnumerable()
});
When I am executing it I catch the error:
System.InvalidOperationException: Unable to translate collection subquery in projection since it uses 'Distinct' or 'Group By' operations and doesn't project key columns of all of it's tables which are required to generate results on client side. Missing column: t.ID. Either add column(s) to the projection or rewrite query to not use 'GroupBy'/'Distinct' operation.
at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.
....
The problem is here .GroupBy(g => new { g.LineCategoryID, g.Title }). If I don't group records, the error disappears.
I was trying a lot of cases with GroupBy() and Distinct(). But can't understand why this is happening. Because I just need grouping like this.
Error message says that you have to include Id column in projection. But you can't do that with GroupBy. So rewrite query into two steps (removed not needed includes):
var rawRecords = UnitOfWork.FreeBets
.Where(f => f.FreeBetCards.Any(cards => cards.UserId == request.UserId))
.Select(f => new
{
FreeBetId = f.FreeBetId
LineCategories = f.FreeBetCategories.Select(c => new { c.Id, c.LineCategoryID, c.Title })
.ToList()
})
.AsEnumerable();
var records = rawRecords
.Select(f => new FreeBetDTO
{
FreeBetId = f.FreeBetId
LineCategories = f.LineCategories.GroupBy(g => new { g.LineCategoryID, g.Title })
.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.Key.LineCategoryID,
Title = c.Key.Title
})
});
Similar query, but more optimal:
var query =
from f in UnitOfWork.FreeBets
from c in f.FreeBetCards
where f.FreeBetCards.Any(cards => cards.UserId == request.UserId)
select new { f.FreeBetId, c.LineCategoryID, c.Title };
query = query.Distinct();
var records = query.AsEnumerable()
.GroupBy(f => f.FreeBetId)
.Select(g => new FreeBetDTO
{
FreeBetId = g.Key
LineCategories = g.Select(c =>
new LineCategoryDTO
{
LineCategoryID = c.LineCategoryID,
Title = c.Title
})
.AsEnumerable()
});
I have two collections
var campaigns = new List<Campaigns>();
IEnumerable<CampaignsDb> campaignsFromDB = db.Campaigns
.Where(c => (c.IsDeleted == false))
.OrderBy(c => c.ScheduleTime)
.ToArray();
Next I'm filling one collection from another using foreach() :
foreach (var campaign in campaignsFromDB)
{
campaigns.Add(new Campaigns { CampaignID = campaign.CampaignID, OwnerID = campaign.CreatedBy, AccountID = campaign.AccountID });
}
Can I use Select() linq method instead of foreach loop ?
Unless you need the original empty list to start with (e.g. to add some other campaigns first), you can use:
var campaigns = campaignsFromDB
.Select(c => new Campaigns
{
CampaignID = c.CampaignID,
OwnerID = c.CreatedBy,
AccountID = c.AccountID
})
.ToList();
However, that will still have fetched the complete campaign information from the database in order to populate campaignsFromDB. That's fine if you need that array for some other reason, but if not, you could make it more efficient by putting the projection into the query:
var campaigns = db.Campaigns
.Where(c => !c.IsDeleted)
.OrderBy(c => c.ScheduleTime)
.Select(c => new Campaigns
{
CampaignID = c.CampaignID,
OwnerID = c.CreatedBy,
AccountID = c.AccountID
})
.ToList();
Yes. Just
var campaigns = db.Campaigns
.Where(c => (c.IsDeleted == false))
.OrderBy(c => c.ScheduleTime)
.Select(c => new Campaigns { CampaignID = c.CampaignID, OwnerID = c.CreatedBy, AccountID = c.AccountID })
.ToList();
or if you need the source set from the database too
var campaignsFromDB = db.Campaigns
.Where(c => (c.IsDeleted == false))
.OrderBy(c => c.ScheduleTime)
.ToArray();
var campaigns = campaignsFromDB
.Select(c => new Campaigns { CampaignID = c.CampaignID, OwnerID = c.CreatedBy, AccountID = c.AccountID })
.ToList();
Yes, like this:
var campaigns = db.Campaigns
.Where(c => !c.IsDeleted)
.OrderBy(c => c.ScheduleTime)
.Select(c => new Campaigns
{
CampaignID = c.CampaignID,
OwnerID = c.CreatedBy,
AccountID = c.AccountID
})
.ToList();
Select Label,
(SELECT COUNT(*) from [CourtSessions] cs where cs.iDCity = Cit.ID) as courts,
(Select COUNT(*) from [Cases] c inner join [CourtSessions] cs ON c.ID = cs.iDCase where cs.iDCity = Cit.ID) as csnatures
FROM Cities Cit
Group by Label, id
I tried this but it doesn't work
var data = db.Cities
.GroupBy(a => a.label)
.Select(g => new
{
city = g.Key,
sessions = db.CourtSessions.Include(p => p.CityTB).Count(o => o.CityTB.label == g.Key),
cases = db.Cases.Join(db.CourtSessions, u => u.ID, ui => ui.iDCase, (u, ui) => new { u, ui }).Count(m => m.ui.CityTB.label == g.Key)
});
Where CityTB is a foreign key
Cases (ID ...)
Cities (ID, Label)
CourtSession (ID, iDCase, iDCity ... CasesTB, CityTB)
I am getting this exception
base {System.Exception} = {"LINQ to Entities does not recognize the method 'System.Linq.IQueryable1[LawbookMVC.Models.CourtSession] Include[CourtSession,City](System.Linq.IQueryable1[LawbookMVC.Models.CourtSession], System.Linq.Expressions.Expression1[System.Func2[LawbookMVC.Mod...
Thanks.
Well i solved it, thanks you all
var dat = db.Cities
.GroupBy(a => new { a.label, a.ID})
.Select(g => new
{
city = g.Key.label,
sessions = db.CourtSessions.Count(o => o.iDCity == g.Key.ID),//,
cases = db.Cases.Join(db.CourtSessions, u => u.ID, ui => ui.iDCase, (u, ui) => new { u, ui }).Count(m => m.ui.CityTB.label == g.Key.label)
});
I have the following tables:
Customer => CustomerAccount => Account
I have an nHibernate mapped POCO to each of the tables above as well.
I have the following lambda expression in an object which implements IIdentifier<T>
public Expression<Func<ICustomer, bool>> Filter
{
get { return customer => customer.CustomerNumber == _customerNumber; }
}
Now what I'm trying to do is join the Customer => CustomerAccount => Account tables via a QueryOver<Account>
How do I add the above Filter lamdba, which is of type Customer, to filter by the customer number?
ICustomer customer = null;
ICustomerAccount customerAccount = null;
IAccount account = null;
var query = QueryOver(() => account)
.JoinAlias(() => account.CustomerAccounts, () => customerAccount, JoinType.InnerJoin)
.JoinAlias(() => customerAccount.Customer, () => customer, JoinType.InnerJoin)
.Where(() => customerAccount.EndDate == null)
.And(() => account.IsPreferredAccount == true)
.And(() => ?? Want to add the above Filter() lambda some how here);
Thanks,
Kyle
You could try:
var query = QueryOver(() => account)
.JoinAlias(() => account.CustomerAccounts, () => customerAccount, JoinType.InnerJoin)
.JoinAlias(() => customerAccount.Customer, () => customer, JoinType.InnerJoin)
.Where(() => customerAccount.EndDate == null)
.And(() => account.IsPreferredAccount == true)
.And(Restrictions.Where<ICustomer>(Filter));