Linq to Entities simple group query - sql

How to write (simple) LINQ to Entities query that groups elements by some attribut and count them?
SELECT answernumber, count(answerID) FROM answers
WHERE questionID = id
GROUB BY answernumber
ORDERBY answernumber;
That should be simple but i don't know how to write it.

var query = answers
.GroupBy(a => a.answernumber, a => a, (k, g) => new {answernumber = k, Count = g.Count()})
.OrderyBy(i => i.answernumber);
Or the other way:
var query2 = from a in answers
group a by a. answernumber into g
orderby g.Key
select new { answernumber = g.Key, Count = g.Count() };

Related

.Net Core EntitiyFramework Top Row Of Joined Table

I'm trying to get all students last attended class from database. I wrote tsql code and it works very well howevery i couldn't do the same on entityframework core.
This code below works for me.
select a.student, b.class, b.attend from students a inner join class b on b.id = (
select top 1 id
from class
where student = a.student order by attend desc
)
Also this is my attemp on writing EF query.
datavalue = db.students.join(
db.class, m => m.student,
s => s.student, (m, s) => new joinedstudentswclass { class = s.class, student = m.student }
).tolist();
u should use firstOrDefault to get a single record.
if u wanna order something, you should be used orderBy methods.
.OrderBy(x => x.City) for ascending students
.OrderByDescending(x => x.City) for descending students
the code should be something like
OrderByDescending(x=>x.Students).FirstOrDefault();
Without navigation properties:
var query =
from s in db.students
from c in db.Where(c => c.student == s.student).OrderByDescending(c => c.attend).Take(1)
select new joinedstudentswclass
{
class = c,
student = s
};
var datavalue = query.ToList()
If you have navigation property Classes in student class:
var query =
from s in db.students
from c in s.Classes.OrderByDescending(c => c.attend).Take(1)
select new joinedstudentswclass
{
class = c,
student = s
};
var datavalue = query.ToList()

select some ids from sql in linq

hi I'm using the query below to select studentId and Score from table1 now i want select users that i selected their ids from table2, how i can select it with ids?
i can select users with this query from v in dc.tbl_Students select v but i want select some users that i have their id.
var qBestMan = (from T in (((from tbl_ActPoints in dc.tbl_ActPoints
select new
{
StudentId = (int?)tbl_ActPoints.StudentId,
Score = (int?)tbl_ActPoints.Score
}).Concat(
from tbl_EvaPoints in dc.tbl_EvaPoints
select new
{
StudentId = (int?)tbl_EvaPoints.StudentId,
Score = (int?)tbl_EvaPoints.Score
})))
group T by new
{
T.StudentId
} into g
orderby g.Sum(p => p.Score) descending
select new
{
g.Key.StudentId,
HighScoreUser = g.Sum(p => p.Score)
}).ToArray();
Try something like this:
//qBestMan must be a List, or a IEnumarable and not a Array. Remove the .ToArray() at the end, or substitute it by .ToList()
var Result = from users in dc.tbl_Students
join bestMen in qBestMan on bestMen.StudentId equals users.userid
select new
{
//fields that you want
example = users.example,
other = bestMen.other
};

How to convert this Sql query to LINQ query

can any one to help to convert this below given sql query to linq.
exec sp_executesql N'use db;
WITH Members AS
(
select ROW_NUMBER() OVER (ORDER BY id DESC) as row, num
from tbl
)
Select row, num
from Members
where row BETWEEN #InitialRow AND #EndRow order by row ASC;',N'#InitialRow int,#EndRow int',#InitialRow=0,#EndRow=5
--
thanks,
Here is a way to to it (with #InitialRow=0,#EndRow=5) :
var result = Members
.OrderByDescending(x => x.id)
.Take(5)
.Select((x,i) =>
new { row = i, num = x.num });
With any values:
var result = Members
.OrderByDescending(x => x.id)
.Skip(InitialRow)
.Take(EndRow-InitialRow)
.Select((x,i) =>
new { row = i+InitialRow, num = x.num });

Remove items from a collection in entity framework

I have a function as below :
IEnumerable<Group> GetAllChildren(int parentID)
{
using (Entities db = new Entities())
{
var result = (from x in db.Groups
where x.ParentID == parentID
select x).ToList();
foreach (Group child in result.ToList())
{
result.AddRange(GetAllChildren(child.GroupID));
}
return result;
}
}
In the above function if I pass a group name I get all the children at all levels.
It works as expected.
Now my query looks like something like :
GroupNamesWithCorrespondingEffects
= new ObservableCollection<GroupNameWithCorrespondingEffect>
(from g in db.Groups
select new GroupNameWithCorrespondingEffect
{
GroupID = g.GroupID,
GroupName = g.GroupName,
CorrespondingEffect = g.Master_Effects.Effect
}
);
The above query will give me all the groups.
Now I want to remove all the groups from GroupNamesWithCorrespondingEffects that are children of a group with id == 25.
I have tried .Remove(GetAllChildren(25)) in 2nd query. but I get following error.
Collection.Remove(GroupNameWithCorrespondingEffect) has some invalid arguments.
hope this help you:
var childs = GetAllChildren(25).ToList();
var childIDList = childs.select(u => u.GroupID).ToList();
GroupNamesWithCorrespondingEffects = GroupNamesWithCorrespondingEffects
.Where(u => !childIDList.Contains(u.GroupID)).ToList();

dynamically change LINQ to Entity query

int year = 2009; // get summ of TONS2009 column
var query = from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new
{
OID = g.Key,
TotalTons = g.Sum( ODInfo => ODInfo.TONS2009)
};
IN the expression 'ODInfo => ODInfo.TONS2009', how do I change TONS2009 to TONS2010 or TONS2011 based on the method parameter 'int year' ?
K06a's answer is close but won't work server-side. Try this:
IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Expression<Func<InputType,decimal>> expr)
{
return from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new OutputType
{
OID = g.Key,
TotalTons = g.AsQueryable().Sum(expr)
};
}
var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);
I haven't tried this, but did something similar here.
UPDATE
If you really need to translate input strings (like "2009") to expressions, it's still possible:
string year = "2009";
Type ODInfoType = typeof(ODINFOTYPE); // substitute with the type of ODInfo
ParameterExpression pe = ParameterExpression.Parameter(ODInfoType, "ODInfo");
MemberInfo mi = ODInfoType.GetProperty("TONS" + year);
MemberExpression me = Expression.MakeMemberAccess(pe, mi);
var expr = Expression.Lambda<Func<ODINFOTYPE, decimal>>(me, pe);
Be aware that this is a patch to the extremly evil structure of your database.
You can try something like that:
TotalTons = g.Sum( ODInfo => (year == 2009) ? ODInfo.TONS2009 : ((year == 2010)
? ODInfo.TONS2010 : ODInfo.TONS2011))
Or make it more readable and use { } to split that lambda expression into more then one line and use eg. switch statement.
The best solution is to break this up into multiple querys that you can compose to a final query:
int year = 2009; // get summ of TONS2009 column
var odInfos =
year == 2009 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2009 })
year == 2010 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2010 })
year == 2011 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2011 })
: null;
var query = from ODInfo in odInfos
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new
{
OID = g.Key,
TotalTons = g.Sum(ODInfo => ODInfo.TONS)
};
This will specialize to three possible queries at runtime, thereby giving the best possible performance. It is better than a case-switch.
Try this way:
IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Func<InputType,decimal> func)
{
return from ODInfo in data
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new OutputType
{
OID = g.Key,
TotalTons = g.Sum(func)
};
}
var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);
Using DynamicLinq which works with EF also:
int year = 2009; // get summ of TONS2009 column
var query = from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select g;
var projectedGroups = query.Select("new (Key as OID, Sum(TONS" + year + ") as TotalTons)");