Lambda convert to LINQ - c#

I don't know anything about lambda, and I can't even read a complicated lambda expression. I have this lambda code below that I want to convert into LINQ, but I don't know how.
var train = db.sample1
.Join(db.sample2, a => a.CertificateId, b => b.CertificateId, (a, b) => new { a, b })
.Where(x => x.a.Year.Value.Year == year && x.a.TrainingTypeId.Value == trainingTypeId && x.a.IsApproved.Value && x.b.EndDate >= DateTime.Now)
.Select(z => z.a).Distinct();
What I have tried so far and got stuck on:
var train = (from c in db.sample1
join in ts sample2 where a.CertificateId equals b.CertificateId
......

Lambda LINQ is still a link expression. However, the statement should look something like this:
var train2 = (from c in db.sample1
join t in db.sample2
on c.CertificateId equals t.CertificateId
where c.Year.Value.Year == year && c.TrainingTypeId.Value == trainingTypeId
&& c.IsApproved.Value && t.EndDate >= DateTime.Now
select c).Distinct();

Related

Using linq to find MIN(date) within linq query

I am using linq to extract data. This data contains a date and some other values. The thing i that these dates can occur more then once, because the dates can have the same value but a different timestamp. I want to extract the anonymous type with the earliest timestamp. How can i do this in linq ?
this is my code:
var result = (from a in UnitOfWork.ActivityLessonParticipantService.Query
.Where(a => a.ActivityLesson.Activity.Id == activityId)
.Where(a => a.ActivityLesson.From >= startDate && (a.ActivityLesson.To == startDate || a.ActivityLesson.To <= endDate)).OrderBy(d => d.ActivityLesson.From)
where !a.ActivityLesson.IsDeleted && !a.ActivityLesson.Activity.IsDeleted && a.Appeared == true
select new
{
CPR = a.User.UserName,
FullName = a.User.FullName,
ActivityFromDate = a.ActivityLesson.From,
}).OrderBy(c => c.CPR).ToList();
thanks
You can GroupBy the Date property of DateTime and then order this group by DateTime and use First to pick only the first record/object:
var query = from a in UnitOfWork.ActivityLessonParticipantService.Query
where a.ActivityLesson.Activity.Id == activityId
&& a.ActivityLesson.From >= startDate
&& (a.ActivityLesson.To == startDate || a.ActivityLesson.To <= endDate)
&& !a.ActivityLesson.IsDeleted
&& !a.ActivityLesson.Activity.IsDeleted
&& a.Appeared
select a;
var firstByDate = query.GroupBy(a => a.ActivityLesson.From.Date)
.Select(grp => grp.OrderBy(a => a.ActivityLesson.From).First())
.OrderBy(a => a.User.UserName)
.Select(a => new
{
CPR = a.User.UserName,
FullName = a.User.FullName,
ActivityFromDate = a.ActivityLesson.From,
}).ToList();
Due to LINQ's deferred execution this is actually a single query that gets executed at the final ToList. I'm mixing query and method syntax because i prefer method syntax when it comes to GroupBy but it's a matter of taste.

LINQ syntax and the where clause

I have written some LINQ but it doesn't return the correct data, it seems to ignore my where clause. Can anybody advise me on what I am doing wrong with the syntax?
IEnumerable<Ranking> lst = (from r in results
join m in membersToRank on r.UserId equals m.userId
join t in teamsToRank on m.teamId equals t.teamId
where r.ResultDate >= rankingStart
&& r.ResultDate <= rankingEnd
select new Ranking
{
memberId = m.memberId,
chain = t.chain,
name = m.name,
teamId = m.teamId,
value = results.Count(i => i.IsCorrect && i.UserId == m.userId)
}).ToList();
This line
value = results.Count(i => i.IsCorrect && i.UserId == m.userId)
will bypass the where clause. You have have to repeat the where there
value = results.Where(...).Count(i => i.IsCorrect && i.UserId == m.userId)
or
var results2 = results.Where(...)
and then use only results2.
(as a sidenote, it will even bypass the join, so it could become a little more complex depending on what you want)

Efficient way to sub Queries in Linq

here is my linq code:
BOOK entity = db.BOOKS
.Where(s => s.ID == (from p in db.LIBRARY
from b in db.BOOKS
where (p.ID == 123) && (p.idpage == b.idpage)
select b.fields));
My actual oracle code is:
SELECT DISTINCT BOOKS.ID
FROM LIBRARY,BOOKS
WHERE LIBRARY.ID = 123 AND LIBRARY.ID = BOOKS.ID
But its showing the error in s.ID that..
Delegate 'System.Func Project.Models.BOOKS,int,bool' does not take 1 arguments
Why does this happen? Are there any workarounds?
Your SQL is using a join, so you can do the same thing in LINQ. Either of these approaches will suffice:
// join
var query = (from b in db.BOOKS
join p in db.LIBRARY on b.IdPage equals p.IdPage
where p.ID == 123
select b.Id).Distinct();
// 2 from statements (SelectMany) can also be used as a join
var query = (from b in db.BOOKS
from p in db.LIBRARY
where p.ID == 123 && b.IdPage == p.IdPage
select b.Id).Distinct();
// fluent syntax
var query = db.BOOKS
.Where(b => db.LIBRARY.Any(p =>
p.ID == 123 && b.IdPage == p.IdPage))
.Select(b => b.Id)
.Distinct();
s.ID is comparing to an Enumerable, so you get the error.
At the end of the LINQ query, add a SingleOrDefault().
Your subquery returns a sequence of values, not a single values, so you can't compare it to a scalar property like ID. You should use First on the result of the subquery to get the first result (or Single if there should be only one)
BOOK entity = db.BOOKS
.Where(s => s.ID == (from p in db.LIBRARY
from b in db.BOOKS
where (p.ID == 123) && (p.idpage == b.idpage)
select b.fields).First());
You should be able to use the navigation properties on your BOOKS class to do something like this:
var bookIds = db.BOOKS.Where(b => b.LIBRARIES.Any(l => l.ID == 123))
.Select(b => b.ID)

Subquery in a Lambda Expression or LINQ

How can you write this query using a lambda expression or LINQ:
SELECT *
FROM vehicles
WHERE (memo1 like '%CERTIFIED%' OR memo2 = 'CERTIFIED')
AND stockno IN (SELECT stockno FROM udealer2 where ACC='UCERT')
ORDER BY model, days DESC
Not knowing much about your model, here is a blind mechanical translation of your query:
vehicles.Where( v =>
(SqlMethods.Like(v.memo1, "%CERTIFIED%") || v.memo2 == "CERTIFIED") &&
udealer2.Any(d => d.ACC == "UCERT" && d.stockno == v.stockno)
).OrderBy(v => v.model)
.ThenByDescending(v => v.days)
where Dealers.Any(d => d.Account == "UCERT" && something.StockNo == d.StockNo)

Linq can these sub queries be optimised?

This query takes a group of comments, then counts their upvotes and downvotes in the tblCommentVotes table.
At the moment, it counts these via the select new statement, in the form of a subquery. Would this be more efficient if it was in some sort of group by in the main query? Also if it would, could anyone show me how to do this, as I can't work out how you would do this.
// Get comments
var q = (
from C in db.tblComments
where
C.CategoryID == Category &&
C.IdentifierID == Identifier
join A in db.tblForumAuthors on C.UserID equals A.Author_ID
orderby C.PostDate descending
select new
{
C,
A.Username,
UpVotes = (from V in db.tblCommentVotes where V.CommentID == C.ID && V.UpVote == true select new { V.ID }).Count(),
DownVotes = (from V in db.tblCommentVotes where V.CommentID == C.ID && V.UpVote == false select new { V.ID }).Count()
}
)
.Skip(ToSkip > 0 ? ToSkip : 0)
.Take(ToTake > 0 ? ToTake : int.MaxValue);
What you need to do is to do an left outer join of the db.tblCommentVotes in the query expression, cause probably there might be no commentVotes?
When you have that, you should be able to perform ONE query in order to get your result.
It might look like this:
var q = (
from C in db.tblComments
where
C.CategoryID == Category &&
C.IdentifierID == Identifier
join A in db.tblForumAuthors on C.UserID equals A.Author_ID
// the following two lines are the left outer join thing.
join voteTemp in db.tblCommentVotes on voteTemp.CommentID equals C.ID into voteJoin
from vote in voteJoin.DefaultIfEmpty()
orderby C.PostDate descending
group C by new { Comment = C, Username = A.Username } into g
select new
{
g.Key.Comment,
g.Key.Username,
UpVotes = g.Count(x => x.UpVote),
DownVotes = g.Count(x => !x.UpVote)
}
)
.Skip(ToSkip > 0 ? ToSkip : 0)
.Take(ToTake > 0 ? ToTake : int.MaxValue);
This is untested and might not even compile, but I think it should be something like this.
db.tblComments.Where(c => c.CategoryID == Category && c.IdentifierID == Identifier)
.Join(db.tblForumAuthors, c => c.UserID, a => a.Author_ID,
(c, a) =>
new
{
CommentID = c,
AuthorName = a.UserName,
UpVotes = c.Join(db.tblCommentVotes, c => c.CommentID
v => v.CommentID,
(c, v) => v).Count(v => v.UpVote)
DownVotes = c.Join(db.tblCommentVotes, c => c.CommentID
v => v.CommentID,
(c, v) => v).Count(v => v.DownVote)
});
To optimise it's best first to measure.
Try, using something like LinqPad to view the generated SQL
Then use SQL Server Management Studio to see the query plan for that SQL
or:
Try running the code and seeing what SQL trace tells you is happening
Without the DB, it's quite hard (but fun) to guess whether that Linq will result in a single query or in multiple queries for working out the UpVotes and DownVotes. My guess is that calculating the UpVotes and DownVotes this way could be quite expensive - it may result in 2 additional queries per comment.
http://www.thereforesystems.com/view-query-generate-by-linq-to-sql/
without analyzing whats being output this question is impossible to answer.. however the link provided above should give you the tools necessary to perform this analysis yourself.

Categories

Resources