I have some Linq code, that works fine. It retrieves a list of board posts ordered by the most recent.
The catch here is the order by ... it orders by the most recent COMMENTS. So if a board post just got a comment, then it will be up the top of the list (ie. most recent).
kewl ... but what about new board posts that just got created? They are listed down the bottom, because they have NO comments :( It's like i want to say "order by most recent comments .. but if u have no comment, then its by your board post create date)".
here's my linq...
boardPostList = (from bp in db.tblBoardPosts.Where(whereClause)
orderby (from bc in bp.tblBoardComments
orderby bc.DateModified descending
select bc.DateModified).First() descending
select bp).ToPagedList(pageNumber, numberOfResults);
Does anyone have any suggestions?
Is there any reason you can't update a field in tblBoardPosts whenever a comment is posted to it? Keep the "posted or last comment" date, then you've got a much simpler query, and one which doesn't need to scan every comment in the system to work out what to do.
Having said that, this query might work, if your DateModified field is nullable:
boardPostList = (from bp in db.tblBoardPosts.Where(whereClause)
orderby ((from bc in bp.tblBoardComments
orderby bc.DateModified descending
select bc.DateModified).FirstOrDefault() ?? bp.DateModified) descending
select bp).ToPagedList(pageNumber, numberOfResults);
If it's just a straight DateTime column, the result of FirstOrDefault is still a DateTime which would be non-nullable... You could try:
boardPostList = (from bp in db.tblBoardPosts.Where(whereClause)
let lastComment = bp.tblBoardComments
.OrderByDescending(bc => bc.DateModified)
.FirstOrDefault()
let lastModified = (lastComment == null
? bp.DateModified
: lastComment.DateModified)
orderby lastModified descending
select bp).ToPagedList(pageNumber, numberOfResults);
It's pretty hideous though, and may not translate into SQL properly. I would certainly try to change to a scheme where the post itself keeps track of it.
Related
I hope one can help me, I am new in linq,
I have 2 tables name tblcart and tblorderdetail:
I just show some fields in these two tables to show whats my problem:
tblCart:
ID,
CartID,
Barcode,
and tblOrderDetail:
ID,
CartID,
IsCompleted
Barcode
when someone save an order, before he confirms his request,one row temporarily enter into the tblCart,
then if he or she confirms his request another row will be inserted into the tblOrderDetail ,
Now I wanna not to show the rows that is inserted into tblOrderDetailed(showing just temporarily rows which there is in tblCart),
In another words, if there is rows in tblCart with cartID=1 and at the same time there is the same row with CartID= 1 in tblOrderDetail, then I dont want that Row.
All in all, Just the rows that there isnt in tblOrderDetail, and the field to realize this is CartID,
I should mention that I make Iscompleted=true, and with that either we can exclude the rows we do not want,
I did this:
var cartItems = context.tblCarts
.Join(context.tblSiteOrderDetails,
w => w.CartID,
orderDetail => orderDetail.cartID,
(w,orderDetail) => new{w,orderDetail})
.Where(a=>a.orderDetail.cartID !=a.w.CartID)
.ToList()
however it doesn't work.
one example:
tblCart:
ID=1
CartID=1213
Barcode=4567
ID=2
CartID=1214
Barcode=4567
ID=3
CartID=1215
Barcode=6576
tblOrderDetail:
ID=2
CartID=1213
Barcode=4567
IsCompleted=true
with these data it should just show the last two Row in tblCart, I mean
ID=2
CartID=1214
Barcode=4567
ID=3
CartID=1215
Barcode=6576
This sounds like a case for WHERE NOT EXISTS in sql.
roughly translated this should be something like this in LINQ:
var cartItems = context.tblCarts.Where(crt => !context.tblSiteOrderDetails.Any(od => od.CartID == crt.cartID));
If you have a navigation property on cart to reference details (I'll assume it's called Details), then:
var results=context.tblCarts.Where(c=>!c.Details.Any(d=>d.IsCompleted));
I'm trying to find duplicates in linq by a particular column (the name column), but I also wish to return the unique id, as I wish to bind to the ID to display additional information about the row.
I've dug around on stackoverflow, but can only find ways of finding duplicates in the fashion off:
By the whole object
By a particular property
Getting the number of duplicates
The closest thing I could find was by specifying "Key" in my group by, but I'm ensure if that is working.
Ideally I'm hoping to output something that has the ID, Number of Duplicates.
Thanks
Assume you have people collection:
from p in people
group p by p.Name into g
select new {
Name = g.Key,
NumberOfDuplicates = g.Count(),
IDs = g.Select(x => x.ID)
}
When I use the following Linq query in LinqPad I get 25 results returned:
var result = (from l in LandlordPreferences
where l.Name == "Wants Student" && l.IsSelected == true
join t in Tenants on l.IsSelected equals t.IsStudent
select new { Tenant = t});
result.Dump();
When I add .Distinct() to the end I only get 5 results returned, so, I'm guessing I'm getting 5 instances of each result when the above is used.
I'm new to Linq, so I'm wondering if this is because of a poorly built query? Or is this the way Linq always behaves? Surely not - if I returned 500 rows with .Distinct(), does that mean without it there's 2,500 returned? Would this compromise performance?
It's a poorly built query.
You are joining LandlordPreferences with Tenants on a boolean value instead of a foreign key.
So, most likely, you have 5 selected land lords and 5 tenants that are students. Each student will be returned for each land lord: 5 x 5 = 25. This is a cartesian product and has nothing to do with LINQ. A similar query in SQL would behave the same.
If you would add the land lord to your result (select new { Tenant = t, Landlord = l }), you would see that no two results are actually the same.
If you can't fix the query somehow, Distinct is your only option.
I have a database with customers orders.
I want to use Linq (to EF) to query the db to bring back the last(most recent) 3,4...n orders for every customer.
Note:
Customer 1 may have just made 12 orders in the last hr; but customer 2 may not have made any since last week.
I cant for the life of me work out how to write query in linq (lambda expressions) to get the data set back.
Any good ideas?
Edit:
Customers and orders is a simplification. The table I am querying is actually a record of outbound messages to various web services. It just seemed easer to describe as customers and orders. The relationship is the same.
I am building a task that checks the last n messages for each web service to see if there were any failures. We are wanting a semi real time Health status of the webservices.
#CoreySunwold
My table Looks a bit like this:
MessageID, WebserviceID, SentTime, Status, Message, Error,
Or from a customer/order context if it makes it easer:
OrderID, CustomerID, StatusChangedDate, Status, WidgetName, Comments
Edit 2:
I eventually worked out something
(Hat tip to #StephenChung who basically came up with the exact same, but in classic linq)
var q = myTable.Where(d => d.EndTime > DateTime.Now.AddDays(-1))
.GroupBy(g => g.ConfigID)
.Select(g =>new
{
ConfigID = g.Key,
Data = g.OrderByDescending(d => d.EndTime)
.Take(3).Select(s => new
{
s.Status,
s.SentTime
})
}).ToList();
It does take a while to execute. So I am not sure if this is the most efficient expression.
This should give the last 3 orders of each customer (if having orders at all):
from o in db.Orders
group o by o.CustomerID into g
select new {
CustomerID=g.Key,
LastOrders=g.OrderByDescending(o => o.TimeEntered).Take(3).ToList()
}
However, I suspect this will force the database to return the entire Orders table before picking out the last 3 for each customer. Check the SQL generated.
If you need to optimize, you'll have to manually construct a SQL to only return up to the last 3, then make it into a view.
You can use SelectMany for this purpose:
customers.SelectMany(x=>x.orders.OrderByDescending(y=>y.Date).Take(n)).ToList();
How about this? I know it'll work with regular collections but don't know about EF.
yourCollection.OrderByDescending(item=>item.Date).Take(n);
var ordersByCustomer =
db.Customers.Select(c=>c.Orders.OrderByDescending(o=>o.OrderID).Take(n));
This will return the orders grouped by customer.
var orders = orders.Where(x => x.CustomerID == 1).OrderByDescending(x=>x.Date).Take(4);
This will take last 4 orders. Specific query depends on your table / entity structure.
Btw: You can take x as a order. So you can read it like: Get orders where order.CustomerID is equal to 1, OrderThem by order.Date and take first 4 'rows'.
Somebody might correct me here, but i think doing this is linq with a single query is probably very difficult if not impossible. I would use a store procedure and something like this
select
*
,RANK() OVER (PARTITION BY c.id ORDER BY o.order_time DESC) AS 'RANK'
from
customers c
inner join
order o
on
o.cust_id = c.id
where
RANK < 10 -- this is "n"
I've not used this syntax for a while so it might not be quite right, but if i understand the question then i think this is the best approach.
I am trying to figure out the best way of getting the record count will incorporating paging. I need this value to figure out the total page count given a page size and a few other variables.
This is what i have so far which takes in the starting row and the page size using the skip and take statements.
promotionInfo = (from p in matches
orderby p.PROMOTION_NM descending
select p).Skip(startRow).Take(pageSize).ToList();
I know i could run another query, but figured there may be another way of achieving this count without having to run the query twice.
Thanks in advance,
Billy
I know i could run another query, but figured there may be another way of achieving this count without having to run the query twice.
No, you have to run the query.
You can do something like:
var source = from p in matches
orderby p.PROMOTION_NM descending
select p;
var count = source.Count();
var promotionInfo = source.Skip(startRow).Take(pageSize).ToList();
Be advised, however, that Skip(0) isn't free.