Linq select a record based on child table data - linq

Trying to select orders based on their current status which is stored in a another table. Keep getting all orders instead of orders filtered by current status. When status is not empty, the query should filter based on the latest status of the order which I think should be status in descending order of date of record taking the first status.
private IQueryable<order_tbl> CreateQuery(string status, int? orderId, DateTime? orderDate) {
var query = from o in context.order_tbl select o;
if (orderId.HasValue) query = query.Where(w => w.id.Equals(orderId.Value));
if (orderDate.HasValue) query = query.Where(w => w.OrderDate.Equals(orderDate.Value));
if (!string.IsNullOrEmpty(status)) {
query = (from q in query
from s in q.order_status
.OrderByDescending(o => o.DateStatusUpdated)
.Take(1)
.Where(w => w.Status.Equals(status))
select q);
}
return query;
}
There are more fields in the tables which I omitted for brevity.
order_tbl
id date customerId
1 2/1/2018 6
2 2/3/2018 5
3 2/6/2018 3
order_status
id orderId DateStatusUpdated status
1 1 2/1/2018 open
2 1 2/2/2018 filled
3 2 2/3/2018 open
4 2 2/4/2018 filled
5 3 2/6/2018 open
When searching only on 'open', the query will return orders 1,2,3 instead of just order 3. What is wrong with the query on the status?

This answer pointed me in the right direction, LINQ Query - Only get Order and MAX Date from Child Collection
Modified my query to the below.
if (!string.IsNullOrEmpty(status)) {
{
query = query
.SelectMany(s => s.order_status
.OrderByDescending(o => o.DateStatusUpdated)
.Take(1)
)
.Where(w => w.Status.Equals(status))
.Select(s => s.order_tbl);
}

Related

Linq - Inner join with group with sum

I have 2 tables, first table if transactions
transaction table:
Id LoanId
1 100
The second table I have is a TransactionLeg table
transactionleg table:
ID TransactionId GLAmount
1 1 200
2 1 200
I would like to join the two on the TransactionId column, group by the loanID and sum the GLAmount
So it should produce the following:
LoanId TotalGlAmount
100 400
var investmentsWritten = from transaction in ctx.Transactions
join transactionleg in ctx.TransLegs on transaction.Id equals transactionleg.TransactionId
where
transaction.Class == Transaction.TransactionClasses.WriteOff &&
transaction.Created >= StartDate.Date && transaction.Created <= EndDate.Date
group transaction by transaction.LoanId
into g
select new { Id = g.Key, Value = _____ };
I was wondering what goes where the underline is, the value is transactionleg.GLAmount. I tried g.Sum(x => x.GLAmount) but GLAmount is not recognized, it is highlighted in red stating Cannot resolve symbol GLAmount
It is because GLAmount is in transactionleg not in transaction,
Modify your group by like this:
group new
{
transaction,
transactionleg
}
by new
{
transaction.LoanId
}
and now in Select:
select new
{
Id = g.Key,
Value = g.Sum(x=>x.transactionleg.GLAmount)
}

Sorting issue with LINQ query and join using tables from different databases

I'm having trouble writing my LINQ query.
Here's the scenario:
I have 2 databases: A and B
In database A: I have a tableX which has the following fields: Employee ID, Name, Address, Phone, ..., Active
In database B: I have a tableY which has the following fields: Employee ID, Visible, Order
the number of records in table Y is less than or equal to the number of records in table X.
Basically, I need to extract the employee records from table X who have the attribute 'Visible' (in table Y) set to True and would like to sort them using the 'Order' attribute.
This is what I have so far:
ADataContext dbA = new ADataContext();
BDataContext dbB = new BDataContext();
//Get the list of records from tableY where 'Visbile' is set to True
var List = dbB.tableY
.Where(x => x.Visible == true).OrderBy(x => x.Order)
.ToList();
//Extract the list of employee IDs
IEnumerable<int> ids = List.Select(x => x.EmployeeID).Distinct();
var employees = dbA.tableX
.Where(x => ids.Contains(x.EmployeeID) && x.Active == true)
.ToList();
I'm able to get the correct list of employees, but cannot figure out how to apply the sorting order (present in tableY) on tableX
Currently, regardless of the order specified in tableY, the records returned from tableX are sorted as they were entered in the table (oldest to most recent).
Any ideas how I can fix my query.
Thanks,
I've re-written it all as a single query:
var employees =
from x in dbA.tableX
where x.Active
from y in dbB.tableY
where x.EmployeeID == y.EmployeeID
orderby y.Order
select x;

LINQ Select Row with Max date per group

I want to return all the values from my "Categories" table and join that to my "CategorySelections" table to display all the categories and whether the specified user selected them or not.
A complication (which I don't know how to deal with in LINQ) is that the user could have changed his selection/deselection of a particular category over time...each change would have logged in the "CategorySelections" table with a date stamp.
I am after the last selection status.
The following SQL query does what I want:
SELECT cs.UserId, c.CategoryId, m.MaxDate, cs.IsSelected
FROM [myDB].[dbo].[Categories] c
LEFT JOIN [myDB].[dbo].[CategorySelections] cs
ON c.CategoryID = cs.CategoryID AND cs.UserID = 7
INNER JOIN
(
SELECT UserId, CategoryId, Max(CreatedOn) as MaxDate
FROM [myDB].[dbo].[CategorySelections]
GROUP BY UserId, CategoryId
) m
ON cs.UserID = m.UserID AND cs.CategoryID = m.CategoryID AND cs.CreatedOn = m.MaxDate
ORDER BY cs.CategoryI
I need some help getting this done in LINQ.
Below is my attempt, which returns all the selections instead of just the last per category.
var query = from c in db.Category
join cs in db.CategorySelection.Where(x => x.UserID == WebSecurity.CurrentUserId)
on c.CategoryID equals cs.CategoryID into JoinedCategory
from cs in JoinedCategory.DefaultIfEmpty()
select new Selection() { CategoryID = c.CategoryID, CategoryName = c.CategoryName ,IsSelected = cs != null ? cs.IsSelected : false }
I am working in MVC; the "new Selection()" refers to my Model
You may add WHERE statement:
where cs.CreatedOn == CategorySelections.Where(t => t.CategoryId == cs.CategoryId).Max(r => r.CreatedOn)

Linq query with two sub-queries that group by, one with an average, and one with a max

I have a parent table, parentTable which may or may not have children in childTable. I am looking to get average % complete of any given parent's children, and the MAX(due) (date) of the children where they exist. My SQL is this:
SELECT parentRecord_id, assigned_to,
(SELECT avg(complete)
FROM childTable
WHERE parent_id = parentRecord_id
and deleted IS NULL
GROUP BY parent_id),
(SELECT max(due)
FROM childTable
WHERE parent_id = parentRecord_id
and deleted IS NULL
GROUP BY parent_id
)
FROM parentTable s
WHERE s.deleted IS NULL and assigned_to IS NOT NULL
My result set gives me rows with either correct values for the average and max, or null. In this instance I have to do follow up processing so I could ignore the null values if I was doing a foreach through DataTable rows. However I am trying to do this in Linq and can't figure out how to avoid a System.InvalidOperationException where Linq is trying to cast null to a double. Here is what I've tried so far.
var query8 = from s in db.parentTable
where s.deleted == null
select new
{
ID = s.assigned_to,
Average =
((from t in db.childTable
where t.parent_id == s.strategy_id
group t by new { t.parent_id } into g
select new
{
a0 = g.Average(f0 => f0.complete )
}).FirstOrDefault().a0)
};
foreach (var itm in query8)
{
Console.WriteLine(String.Format("User id:{0}, Average: {1}", itm.ID, itm.Average));
}
Here's my question. How do I get the query to handle those returned rows where average complete or max due (date) are null?
You can either filter out the records where the values are null (by another condition) or if you want to include them do something like this:
a0 = g.Average(f0 => f0.complete.HasValue? f0.complete: 0 )
I would cast the list to nullable double before calling Average/Max like so:
var query8 =
from s in db.parentTable
where s.deleted == null
select new
{
ID = s.assigned_to,
Average =
from t in db.childTable
where t.parent_id == s.strategy_id
group t by t.parent_id into g
select g.Cast<double?>().Average(f0 => f0.complete)
};
Assuming complete is a Nullable, you should be able to do:
var query8 = from s in db.parentTable
where s.deleted == null
select new
{
ID = s.assigned_to,
Average =
((from t in db.childTable
where t.parent_id == s.strategy_id
&& s.complete.HasValue()
group t by new { t.parent_id } into g
select new
{
a0 = g.Average(f0 => f0.complete )
}).FirstOrDefault().a0)
};
Thanks to all who responded.
I was unable get around the null anonymous issue with the basic query as I had it, but adding a join to the childTable eliminated the nulls.
Another solution is to use a from x in g.DefaultIfEmpty clause.
var query8 =
from st in db.tableParent
select new { Ass = st.assigned_to ,
Avg =
(from ta in db.tableChild
group ta by ta.parent_id into g
from x in g.DefaultIfEmpty()
select g.Average((f0=>f0.complete))).FirstOrDefault()
};

Linq query, return distinct on single field & returning subset of data

I have a Linq query that returns three data elements.
var billingDateResults = from s in Subscriptions
.Where(s => (s.ProductCode.Contains("myCode")))
select { g.ID, BillingDate =s.BILL_THRU, s.ProductCode};
I would like to do distinct type of query on this to limit the results to one record per ID.
var billingDateResults = from s in Subscriptions
.Where(s => (s.ProductCode.Contains("myCode")))
group s by s.ID into g
select g.FirstOrDefault();
This works but now returns all of the fields in the records and I would like to minimize the amount of data by limiting the results to only the 3 fields in the first example.
What is a good way to do this?
TIA
Group by those three fields then.
var billingDateResults =
from s in Subscriptions
where s.ProductCode.Contains("myCode")
group new
{
g.ID,
BillingDate = s.BILL_THRU,
s.ProductCode
} by s.ID into g
select g.First(); // FirstOrDefault is not necessary, the groups will be non-empty

Resources