I am trying to exclude items that have a.id that exists in db.AdminAdjusterStatus.
from u in db.Users
join a in db.Adjusters on u.id equals a.userID
where u.userType.ToLower() == "adjuster"
&& !(from x in db.AdminAdjusterStatus select x.adjusterID).Contains(a.id)
select new AdjusterProfileStatusItem { user = u, adjuster = a }
The code above says, "where NOT contains a.id in db.AdminAdjusterStatus.adjusterID.
The problem is, it doesn't work. I have these two entries in db.AdminAdjusterStatus:
A9EC05B5-651D-4AA7-8275-1F6BFE212C03
1BDE55D9-ED0A-4854-9D5F-B89DB17F02D2
And, the LINQ query gives me:
A9EC05B5-651D-4AA7-8275-1F6BFE212C03
1BDE55D9-ED0A-4854-9D5F-B89DB17F02D2
e21ff49c-9505-495d-b4a3-c259ee3459d6
Whereas, it should only give me:
e21ff49c-9505-495d-b4a3-c259ee3459d6
var query = from u in db.Users
from a in db.Adjusters
where u.userType.ToLower() == "adjuster" &&
u.id == a.userID &&
!db.AdminAdjusterStatus.Any(i => i.adjusterID == a.id)
...
You could try doing a Left Join and filtering on the null records. Without having data to test against I cannot say for certain on if it will work "out of the box" but I have used the following code several times for doing filtering like this:
db.Users.Join(db.Abjusters, outer => outer.id, inner => inner.userID, new { User = outer, Adjuster = inner })
.GroupJoin(DBConcurrencyException.AdminAdjusterStatus, outer => outer.Adjuster.id, inner => inner.adjusterID, new { User = outer.User, Adjuster = outer.Adjuster, Admins = inner })
.SelectMany(grp => grp.Admins.DefaultIfEmpty(), (grp, admin) => new { User = grp.User, Adjuster = grp.Adjuster, Admin = admin })
.Where(item => item.User.userType == "adjuster" && item.Admin == null)
.Select(item => new AdjusterProfileStatusItem { user = item.User, adjuster = item.Adjuster });
The GroupJoin/SelectMany combination performs a Left Join and then you can filter where the object is null which should produce the same as a NOT IN.
Thanks to everyone for their help and sorry to waste anyone's time. I realized that this line:
obj.adjusterID = '#(Url.RequestContext.RouteData.Values["id"])';
Elsewhere in my code had been sending u.id instead of a.id as I had thought that it was. Because of this, I was saving the wrong ID in my database, thus resulting in the problem I was experiencing.
Thanks, again for all your help!
Perhaps this could work?
var AdjusterItems = from aa in AdminAdjusterStatus
join a in Adjusters
on aa.AdjusterId equals a.AdjusterId
select a.UserId;
var UsersNotAdjustAdmin = from u in Users
where !AdjusterItems.Any(x => x == u.Id)
&& u.UserType.Equals("Adjuster", StringComparison.InvariantCultureIgnoreCase)
select u;
var result = from u in UsersNotAdjustAdmin
join a in Adjusters
on u.Id equals a.UserId
select new AdjusterProfileStatusItem() { Adjuster = a, User = u };
Related
The following is my code that works. But as you can see I am having to write select twice
var lstCargoRequestVM =
(from c in db.Cargo
join v in db.Vehicles on c.VehicleID equals v.VehicleID
join cmp in db.Companies on c.CompanyID equals cmp.CompanyID
where c.Isdeleted == false && c.IsActive == true
select new CargoRequestVM
{
CargoId = c.CargoID,
CompanyName = cmp.CompanyName,
VehicleNo = v.VehicleNo,
Date = c.DateOfPassage,
Type = c.Type.ToString()
})
.AsEnumerable()
.Select(x => new CargoRequestVM
{
CargoId = x.CargoId,
CompanyName = x.CompanyName,
VehicleNo = x.VehicleNo,
Date = x.Date,
Type = CargoElements.CargoTypeName(x.Type.ToString())
}).ToList();
Is it possible to do the same without having to write select twice? There could be more than a dozen properties in certain case. I don't want to make my code unnecessarily lengthy.
Probably that wouldn't have a translation to underlying database and thus you need to write basically twice. However you can apply the AsEnumerable() after where using method syntax like (assuming you in fact have a good relational schema defined and navigational properties set - in Linq you very rarely need join keyword):
stVM = db.Cargo
.Include( c => c.Vehicle )
.Include( c => c.Company )
.Where( c => !c.Isdeleted && c.IsActive )
.AsEnumerable()
.Select( c => new CargoRequestVM
{
CargoId = c.CargoID,
CompanyName = c.Company.CompanyName,
VehicleNo = c.Vehicle.VehicleNo,
Date = c.DateOfPassage,
Type = CargoElements.CargoTypeName(c.Type.ToString())
}).ToList();
i want to convert this SQL to LINQ but i cant compile it. This is my sql to convert
SELECT u.UserID ,
A.Username ,
A.Password ,
A.CreatedOn
FROM dbo.tbl_User U
INNER JOIN dbo.tbl_UserAuthDetail A ON A.UserID = U.UserID
AND A.CreatedOn IN (
SELECT TOP 1
CreatedOn
FROM dbo.tbl_UserAuthDetail U2
WHERE U2.UserID = U.UserID
ORDER BY CreatedOn DESC )
and this is my attempt so far
var q = from u in context.Users
join au in context.UserAuthDetails on u.UserID equals au.UserID &&
(from au2 in context.UserAuthDetails where au2.UserID == u.UserID orderby au2.CreatedOn descending select au2.CreatedOn).ToList().Contains(au.CreatedOn)
Any help would be appreciated.
TIA
Note: This code is untested but I think you want to get the latest credential of each user.
var query = context.Users
.GroupJoin(context.UserAuthDetails,
u => u.UserID ,
d => d.UserID,
(u, d) => new
{
User = u,
Details = d.OrderByDescending(x => x.CreatedOn).Take(1)
});
You can remove .Take(1) to get all the records of the user and still the result is sorted in descending order.
from u in context.Users
join au in context.UserAuthDetails on u.UserID equals au.UserID &&
context.UserAuthDetails.Where(au2 => au2.UserID == u.UserID)
.OrderByDescending(au2 => au2.CreatedOn)
.Select(au => au2.CreatedOn)
//.Take(1) //you have this in SQL
.Any(auc=>auc == au.CreatedOn)
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)
I need to write following query in Linq to SQL but not sure what is the best way of doing, given it has two derived tables. Any suggestions.
SELECT A.ID
FROM
(
SELECT *
FROM Orders
WHERE ProductID = 5
) A
JOIN
(
SELECT CustomerID, MAX(Price) Price
FROM Orders
WHERE ProductID = 5
GROUP BY CustomerID
) B
ON A.CustomerID = B.CustomerID and A.Price = B.Price
var b = (
from o in db.Orders
where o.ProductID == 5
group o by o.CustomerID into og
select new {
CustomerID = og.Key
Price = Max(og.Price)
}
);
var a = (
from o in db.Orders
join p in b on new {a.CustomerID, a.Price} equals
new {b.CustomerID, b.Price}
where o.ProductID == 5
select a.ID
);
var r = a.ToString();
These two links are invaluable when forming things like this:
http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
http://msdn.microsoft.com/en-us/vstudio/bb688085
Can you simplify this with LINQ, especially if you use method syntax instead of query syntax.
orders.Where(o => o.ProductID == 5)
.GroupBy(o => o.CustomerID)
.SelectMany(g => g.Where(o => o.Price == g.Max(m => m.Price)));
My advice when writing LINQ, do not simply attempt to convert a SQL statement exactly. Think about the desired result and develop a solution designed for LINQ.
Something along these lines:
var result = from a in context.Orders
join b in (context.Orders.Where(o => o.ProductID == 5).GroupBy(o => o.CustomerID).Select(g => new { CustomerID = g.Key, Price = g.Max(o => o.Price)))
on new {a.CustomerID, a.Price} equals new {b.CustomerID, b.Price}
where a.ProductID == 5
select a.ID;
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.