How can I transform this SQL query to LINQ? - c#

How can I transform this SQL query to LINQ?
SELECT eg.Name Name, sum(bi.PlannedAmount) Amount
FROM BudgetItem bi, Expense e, ExpenseGroup eg
WHERE Discriminator = 'ExpenseItem' AND
bi.ExpenseId = e.Id AND
e.ExpenseGroupId = eg.id AND
bi.MonthlyBudgetId = 1
GROUP BY eg.Name
So far I've come up with this line:
var result = context
.ExpenseGroups
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
But I still cannot figure out what expression to use to add 'bi.MonthlyBudgetItem = 1'.
Does anybody have an Idea?
Edit #1:
I forgot to mention the relationships between the entities. Every ExpenseGroup has many Expenses, and every Expense has many BudgetItems.
So, ExpenseGroup => Expenses => BudgetItems
Edit #2:
I'm using Entity Framework and every ExpenseGroup has a Collection of Expense objects (every Expense has a ExpenseGroup object), as well as every Expense has a Collection of BudgetItem objects (every BudgetItem object has a Expense object).

I suppose something like this should do it:
var result = context
.ExpenseGroups
.Where(x => x.Discriminator == 'ExpenseItem' &&
x.bi.ExpenseId == e.Id &&
x.e.ExpenseGroupId == eg.id &&
x.bi.MonthlyBudgetId == 1)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();

Something similar to this...
var result = (from g in context.ExpenseGroups
where g.Expense.BudgetItem.MonthlyBudgetId == 1
select g)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
or
var result = context.ExpenseGroups
.Where(g => g.Expense.BudgetItem.MonthlyBudgetId == 1)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();

You are actually doing an inner join in your SQL query, so do similarly in your linq query as well. This should work:-
var result = from bi in context.BudgetItem
join e in context.Expense
on bi.ExpenseId equals e.Id
where bi.MonthlyBudgetId == 1
join eg in ExpenseGroup
on e.ExpenseGroupId equals eg.id
group new { bi, eg } by eg.Name into g
select new
{
Name = g.Key,
Amount = g.Sum(x => x.bi.PlannedAmount)
};

Related

Only primitive types or enumeration types are supported in this context error [duplicate]

I am getting this error for the query below
Unable to create a constant value of type API.Models.PersonProtocol. Only primitive types or enumeration types are supported in this context
ppCombined below is an IEnumerable object of PersonProtocolType, which is constructed by concat of 2 PersonProtocol lists.
Why is this failing? Can't we use LINQ JOIN clause inside of SELECT of a JOIN?
var persons = db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
new PersonDTO
{
personId = y.personId,
addressId = y.addressId,
favoriteId = x.favoriteId,
personProtocol = (ICollection<PersonProtocol>) ppCombined
.Where(a => a.personId == x.personId)
.Select( b => new PersonProtocol()
{
personProtocolId = b.personProtocolId,
activateDt = b.activateDt,
personId = b.personId
})
});
This cannot work because ppCombined is a collection of objects in memory and you cannot join a set of data in the database with another set of data that is in memory. You can try instead to extract the filtered items personProtocol of the ppCombined collection in memory after you have retrieved the other properties from the database:
var persons = db.Favorites
.Where(f => f.userId == userId)
.Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
new // anonymous object
{
personId = p.personId,
addressId = p.addressId,
favoriteId = f.favoriteId,
})
.AsEnumerable() // database query ends here, the rest is a query in memory
.Select(x =>
new PersonDTO
{
personId = x.personId,
addressId = x.addressId,
favoriteId = x.favoriteId,
personProtocol = ppCombined
.Where(p => p.personId == x.personId)
.Select(p => new PersonProtocol
{
personProtocolId = p.personProtocolId,
activateDt = p.activateDt,
personId = p.personId
})
.ToList()
});
In my case, I was able to resolve the issue by doing the following:
I changed my code from this:
var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();
To this:
var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();
Don't know if anyone searches for this.
I had the same problem. A select on the query and then doing the where (or join) and using the select variable solved the problem for me.
(problem was in the collection "Reintegraties" for me)
query.Select(zv => new
{
zv,
rId = zv.this.Reintegraties.FirstOrDefault().Id
})
.Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
&& t.HoortBijEntiteitType == EntiteitType.Reintegratie
&& t.Type == TaakType))
.Select(x => x.zv);
hope this helps anyone.
I had this issue and what I did and solved the problem was that I used AsEnumerable() just before my Join clause.
here is my query:
List<AccountViewModel> selectedAccounts;
using (ctx = SmallContext.GetInstance()) {
var data = ctx.Transactions.
Include(x => x.Source).
Include(x => x.Relation).
AsEnumerable().
Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
ToList();
}
I was wondering why this issue happens, and now I think It is because after you make a query via LINQ, the result will be in memory and not loaded into objects, I don't know what that state is but they are in in some transitional state I think. Then when you use AsEnumerable() or ToList(), etc, you are placing them into physical memory objects and the issue is resolving.
It's worth adding, since the OP's code sample doesn't provide enough context to prove otherwise, but I received this error as well on the following code:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}
Apparently, I cannot use Int32.Equals in this context to compare an Int32 with a primitive int; I had to (safely) change to this:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}
Just add AsEnumerable() andToList() , so it looks like this
db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()
ToList().AsEnumerable()

Comparing list with list inside another list with linq [duplicate]

I am getting this error for the query below
Unable to create a constant value of type API.Models.PersonProtocol. Only primitive types or enumeration types are supported in this context
ppCombined below is an IEnumerable object of PersonProtocolType, which is constructed by concat of 2 PersonProtocol lists.
Why is this failing? Can't we use LINQ JOIN clause inside of SELECT of a JOIN?
var persons = db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
new PersonDTO
{
personId = y.personId,
addressId = y.addressId,
favoriteId = x.favoriteId,
personProtocol = (ICollection<PersonProtocol>) ppCombined
.Where(a => a.personId == x.personId)
.Select( b => new PersonProtocol()
{
personProtocolId = b.personProtocolId,
activateDt = b.activateDt,
personId = b.personId
})
});
This cannot work because ppCombined is a collection of objects in memory and you cannot join a set of data in the database with another set of data that is in memory. You can try instead to extract the filtered items personProtocol of the ppCombined collection in memory after you have retrieved the other properties from the database:
var persons = db.Favorites
.Where(f => f.userId == userId)
.Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
new // anonymous object
{
personId = p.personId,
addressId = p.addressId,
favoriteId = f.favoriteId,
})
.AsEnumerable() // database query ends here, the rest is a query in memory
.Select(x =>
new PersonDTO
{
personId = x.personId,
addressId = x.addressId,
favoriteId = x.favoriteId,
personProtocol = ppCombined
.Where(p => p.personId == x.personId)
.Select(p => new PersonProtocol
{
personProtocolId = p.personProtocolId,
activateDt = p.activateDt,
personId = p.personId
})
.ToList()
});
In my case, I was able to resolve the issue by doing the following:
I changed my code from this:
var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();
To this:
var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();
Don't know if anyone searches for this.
I had the same problem. A select on the query and then doing the where (or join) and using the select variable solved the problem for me.
(problem was in the collection "Reintegraties" for me)
query.Select(zv => new
{
zv,
rId = zv.this.Reintegraties.FirstOrDefault().Id
})
.Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
&& t.HoortBijEntiteitType == EntiteitType.Reintegratie
&& t.Type == TaakType))
.Select(x => x.zv);
hope this helps anyone.
I had this issue and what I did and solved the problem was that I used AsEnumerable() just before my Join clause.
here is my query:
List<AccountViewModel> selectedAccounts;
using (ctx = SmallContext.GetInstance()) {
var data = ctx.Transactions.
Include(x => x.Source).
Include(x => x.Relation).
AsEnumerable().
Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
ToList();
}
I was wondering why this issue happens, and now I think It is because after you make a query via LINQ, the result will be in memory and not loaded into objects, I don't know what that state is but they are in in some transitional state I think. Then when you use AsEnumerable() or ToList(), etc, you are placing them into physical memory objects and the issue is resolving.
It's worth adding, since the OP's code sample doesn't provide enough context to prove otherwise, but I received this error as well on the following code:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}
Apparently, I cannot use Int32.Equals in this context to compare an Int32 with a primitive int; I had to (safely) change to this:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}
Just add AsEnumerable() andToList() , so it looks like this
db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()
ToList().AsEnumerable()

LINQ to Entities Select taking a long time

I have a People table with around 1000 rows and a Dramas table with around 100 rows in SQL Azure. The two are linked with a foreign key Drama.PersonId so that each person can have 0 or more dramas.
The code below behaves as expected, returning around 50 people and their associated recent dramas. However, it takes more than 5 seconds to run (measured with a Stopwatch). There must be something inefficient going on?
var people = ctx.People
.Where(p => p.Dramas.Any(d => d.DateHappened >= startDate))
.Select(p => new
{
p.FirstName,
p.LastName,
Dramas = p.Dramas.Where(d => d.DateHappened >= startDate).Select(d => new { d.Id, d.DramaType })
}).AsEnumerable();
I've made this much faster by first fetching all recent dramas and then sending a separate query to get the people. It uses a PredicateBuilder.
var dramasByPerson = ctx.Dramas.Where(d => d.DateHappened >= startDate)
.Select(d => new { d.PersonId, d.Id, d.DramaType })
.ToLookup(d => d.PersonId);
var predicate = dramasByPerson.Select(o => o.Key)
.Aggregate(
PredicateBuilder.False<Person>(),
(current, personId) => current.Or(o => o.PersonId == personId)
);
var dictPeople = ctx.People.Where(predicate)
.Select(o => new { o.PersonId, o.LastName, o.FirstName })
.ToDictionary(o => o.PersonId);
var people = dramasByPerson.Select(o => new {
LastName = people[o.Key].LastName,
FirstName = people[o.Key].FirstName,
Dramas = o.Select(d => new { d.Id, d.DramaType })
});

Unable to create a constant value of type Only primitive types or enumeration types are supported in this context

I am getting this error for the query below
Unable to create a constant value of type API.Models.PersonProtocol. Only primitive types or enumeration types are supported in this context
ppCombined below is an IEnumerable object of PersonProtocolType, which is constructed by concat of 2 PersonProtocol lists.
Why is this failing? Can't we use LINQ JOIN clause inside of SELECT of a JOIN?
var persons = db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
new PersonDTO
{
personId = y.personId,
addressId = y.addressId,
favoriteId = x.favoriteId,
personProtocol = (ICollection<PersonProtocol>) ppCombined
.Where(a => a.personId == x.personId)
.Select( b => new PersonProtocol()
{
personProtocolId = b.personProtocolId,
activateDt = b.activateDt,
personId = b.personId
})
});
This cannot work because ppCombined is a collection of objects in memory and you cannot join a set of data in the database with another set of data that is in memory. You can try instead to extract the filtered items personProtocol of the ppCombined collection in memory after you have retrieved the other properties from the database:
var persons = db.Favorites
.Where(f => f.userId == userId)
.Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
new // anonymous object
{
personId = p.personId,
addressId = p.addressId,
favoriteId = f.favoriteId,
})
.AsEnumerable() // database query ends here, the rest is a query in memory
.Select(x =>
new PersonDTO
{
personId = x.personId,
addressId = x.addressId,
favoriteId = x.favoriteId,
personProtocol = ppCombined
.Where(p => p.personId == x.personId)
.Select(p => new PersonProtocol
{
personProtocolId = p.personProtocolId,
activateDt = p.activateDt,
personId = p.personId
})
.ToList()
});
In my case, I was able to resolve the issue by doing the following:
I changed my code from this:
var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();
To this:
var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();
Don't know if anyone searches for this.
I had the same problem. A select on the query and then doing the where (or join) and using the select variable solved the problem for me.
(problem was in the collection "Reintegraties" for me)
query.Select(zv => new
{
zv,
rId = zv.this.Reintegraties.FirstOrDefault().Id
})
.Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
&& t.HoortBijEntiteitType == EntiteitType.Reintegratie
&& t.Type == TaakType))
.Select(x => x.zv);
hope this helps anyone.
I had this issue and what I did and solved the problem was that I used AsEnumerable() just before my Join clause.
here is my query:
List<AccountViewModel> selectedAccounts;
using (ctx = SmallContext.GetInstance()) {
var data = ctx.Transactions.
Include(x => x.Source).
Include(x => x.Relation).
AsEnumerable().
Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
ToList();
}
I was wondering why this issue happens, and now I think It is because after you make a query via LINQ, the result will be in memory and not loaded into objects, I don't know what that state is but they are in in some transitional state I think. Then when you use AsEnumerable() or ToList(), etc, you are placing them into physical memory objects and the issue is resolving.
It's worth adding, since the OP's code sample doesn't provide enough context to prove otherwise, but I received this error as well on the following code:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}
Apparently, I cannot use Int32.Equals in this context to compare an Int32 with a primitive int; I had to (safely) change to this:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}
Just add AsEnumerable() andToList() , so it looks like this
db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()
ToList().AsEnumerable()

Entity Framework with Linq, inner Join, Group By, Order By

I have a SQL Query
select Firma.Name as companyName,
Taetigkeit.Taetigkeit as skillName,
SUM(Zeit) as time
from Zeiterfassung
inner join Firma On ZEiterfassung.FirmenID = Firma.ID
inner join Taetigkeit on Zeiterfassung.TaetigkeitID = Taetigkeit.ID
group by Taetigkeit, Firma.Name
order by Firma.Name
And want to "translate" it to linq. Here is what I tried:
var query = db.Zeiterfassung
.Where(x => x.Firma.ID == x.FirmenID && x.TaetigkeitID == x.Taetigkeit.ID)
.GroupBy(x => x.Taetigkeit.Taetigkeit1)
.Select(x => new Evaluation() { skillName = x.Key, time = x.Sum(y => y.Zeit), //skillName = x.Sum(x => x.Zeit), })
.OrderBy(x => x.skillName);
I dont know who to solve this with joins and the group by because all the time when i do a groupBy i cant access the other members.
From data you provided, I think query should look like
from z in db.Zeiterfassung
join f in db.Firma on z.FirmenID equals f.ID
join t in db.Taetigkeit on z.TaetigkeitID equals t.ID
select new { f.Name, t.Taetigkeit, z.Zeit) into x
group x by new { x.Taetigkeit, f.Name } into g
select new {
CompanyName = g.Key.Name,
SkillName = g.Key.Taetigkeit,
Time = g.Sum(i => i.Zeit)
}
Or with navigation properties:
db.Zeiterfassung
.Select(z => new { z.Zeit, z.Taetigkeit.Taetigkeit1, z.Firma.Name })
.GroupBy(x => new { x.Taetigkeit1, x.Name })
.Select(g => new Evaluation {
companyName = g.Key.Name,
skillName = g.Key.Taetigkeit1,
time = g.Sum(y => y.Zeit)
});

Categories

Resources