Using Lambda to query collection / joined table - c#

I have a lambda 'where' query, querying an Order table like this:
List<Order> returnedOrders = _session.Query<Script>()Where(s => s.orderId == orderIdParam).ToList();
I want to also check the value of a column in the related OrderDetails table. So returnedOrders has a collection of OrderDetails, i.e. returnedOrders.orderDetails
So the SQL query would look something like:
Where OrderId = 12345 and Order.OrderDetail.CreatedDate = '01-Jan-2013'
Can anyone help me with the correct syntax please?

You can use a logical AND (&&) inside the Where method:
var date = new Date(2013,1,1);
List<Order> returnedOrders =
_session.Query<Script>()
.Where(s =>
s.orderId == orderIdParam &&
s.OrderDetails.Any(d => d.CreatedDate == date))
.ToList();
You can alternatively append another Where method.
var date = new Date(2013,1,1);
List<Order> returnedOrders =
_session.Query<Script>()
.Where(s => s.orderId == orderIdParam)
.Where(s => s.OrderDetails.Any(d => d.CreatedDate == date))
.ToList();

Since you know Id of order it seems useless but something like this
from order in orders
from detail in order.Details
where
order.Id = orderId &&
order.Id == detail.OrderId &&
detail.CreateDate == createDate
select order

Related

How to convert Lambda Expression into SQL exp?

I am having difficulty converting this expression to SQL expression. I tried various applications but I failed. I tried to convert it myself but the result is different.
db.Trans_SAPStat.Where(s => s.EmployeeID == EmployeeID && s.PaymentID != PaymentID && !s.Status.Equals("cancelled or", StringComparison.OrdinalIgnoreCase))
.Join(_db.Trans_PaymentDetail,
stat => stat.PaymentID,
paydet => paydet.PaymentID,
(stat, paydet) => new
{
InvoiceNo = paydet.Remarks,
paydet.Amount,
stat.Status,
paydet.PaymentCode
})
.Where(s => s.PaymentCode.ToLower() == "c")
.GroupBy(g => g.InvoiceNo)
.Select(lg =>
new
{
InvoiceNo = lg.Key,
TotalAmount = lg.Sum(w => w.Amount)
}).ToList();
If you have this code inside working application then try to use SQL profiler. Another option - linqpad
Try this:
SELECT
p.Remarks AS InvoiceNo,SUM(p.Amount) AS TotalAmount
FROM Trans_SAPStat AS s
INNER JOIN Trans_PaymentDetail AS p ON s.PaymentID = p.PaymentID
WHERE s.EmployeeID = #EmployeeID
AND s.PaymentID <> #PaymentID
AND LOWER(s.Status) <> 'cancelled or'
AND LOWER(s.PaymentCode) = 'c'
GROUP BY p.Remarks
You can try to set the query to a variable without materialization (.ToList()), then just use query.ToString(). This will return the actual SQL query.
var query = db.Trans_SAPStat.Where(....); // don't call .ToList()
var sqlQuery = query.ToString();
var result = query.ToList(); // materialization
NOTE: This is the default behaviour for entity framework / linq to entities IQueryable<T> interface.

Ability to conditionally choose what row to select

This is mostly to see if I can find a way to work around this limitation.
Let's say I have the following query:
var query = (from a in db.Table
where a.CustomFieldId == FieldID && a.ListingId == listingID
select a.SomeTypeValue);
The table I am querying is set for custom fields that may vary in type, so it has several columns but only uses the appropriate column to store the value based on the field's selected type.
The table looks somewhat like this:
I want to be able to choose which column I select without rewriting the whole query. Is this possible?
Thanks in advance,
Your query can be rewrited to use "Method Call LINQ":
db.Table
.Where(a => a.CustomFieldId == FieldID && a.ListingId == listingID)
.Select(x => x.SomeType);
You may split query into Where and Select parts then:
var result = whereQuery.Select(x => x.BoolValue);
or
var result = whereQuery.Select(x => x.IntValue);
You may even encapsulate that logic into method:
IEnumerable<T> GetValues<T>() {
var query = db.Table
.Where(a => a.CustomFieldId == FieldID && a.ListingId == listingID);
if (typeof(T)==typeof(bool)) {
return query.Select(x => x.BoolColumn);
}
else if (typeof(T) == typeof(int)) {
return query.Select(x => x.IntColumn);
}
// other types here
}

LINQ to Entity join query

I have the following setup:
Table ShoeAreas that has columns ShoeId and MaterialId.
Table Shoes that has columns ID and Status.
I have a method that takes one argument - materialId and the goal is to determine if there is a record in ShoeAreas with a MaterialId equal to the one passed like an argument. And if such a record (or records most probably) exist if they are relateed to shoe from Shoes withStatus` = Production.
I tried this :
return shoeService.All().
Join(shoeAreaService.All(),
s => s.ID,
sa => sa.ShoeId,
(s, sa) => (sa.MaterialId == matId)).
Any(s => (s.Status == (byte)EntityStatusProd.Production)));
But I get error on the Any.. line saying } expected and also this is my second Linq to Entity query that I write so I have doubts if it's syntax problem or the query is wrong itself.
You are returning IEnumerable<bool> from Join method (values of condition sa.MaterialId == matId). Create anonymous type which will hold both joined entities instead:
return shoeService.All()
.Join(shoeAreaService.All(),
s => s.ID,
sa => sa.ShoeId,
(s, sa) => new { s, sa }) // here
.Any(x => (x.sa.MaterialId == matId) &&
(x.s.Status == (byte)EntityStatusProd.Production)));
you can try this: (linq )
from shoe in Shoes
join shoeArea in ShoesArea on shoe.ID equals shoeArea.ShoeID
where shoeArea.MeterialID == matID && shoe.Status == (byte)EntityStatusProd.Production
select new {shoe.ID,shoe.Status};
return shoeService.All().Any(s => shoeAreaService.All()
.Any(sa => sa.MaterialId == matId
&& s.Id == sa.ShoeId)
&& s.Status == (byte)EntityStatusProd.Production);

LINQ Using Max() to select a single row

I'm using LINQ on an IQueryable returned from NHibernate and I need to select the row with the maximum value(s) in a couple of fields.
I've simplified the bit that I'm sticking on. I need to select the one row from my table with the maximum value in one field.
var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) }
from u in table
group u by 1 into g
where u.Status == g.Max(u => u.Status)
select u
This is incorrect but I can't work out the right form.
BTW, what I'm actually trying to achieve is approximately this:
var clientAddress = this.repository.GetAll()
.GroupBy(a => a)
.SelectMany(
g =>
g.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.AddressReference == g.Max(x => x.AddressReference) &&
a.StartDate == g.Max(x => x.StartDate)))
.SingleOrDefault();
I started with the above lambda but I've been using LINQPad to try and work out the syntax for selecting the Max().
UPDATE
Removing the GroupBy was key.
var all = this.repository.GetAll();
var address = all
.Where(
a =>
a.Reference == clientReference &&
a.Status == ClientStatus.Live &&
a.StartDate == all.Max(x => x.StartDate) &&
a.AddressReference == all.Max(x => x.AddressReference))
.SingleOrDefault();
I don't see why you are grouping here.
Try this:
var maxValue = table.Max(x => x.Status)
var result = table.First(x => x.Status == maxValue);
An alternate approach that would iterate table only once would be this:
var result = table.OrderByDescending(x => x.Status).First();
This is helpful if table is an IEnumerable<T> that is not present in memory or that is calculated on the fly.
You can also do:
(from u in table
orderby u.Status descending
select u).Take(1);
You can group by status and select a row from the largest group:
table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First();
The first First() gets the first group (the set of rows with the largest status); the second First() gets the first row in that group.
If the status is always unqiue, you can replace the second First() with Single().
Addressing the first question, if you need to take several rows grouped by certain criteria with the other column with max value you can do something like this:
var query =
from u1 in table
join u2 in (
from u in table
group u by u.GroupId into g
select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) }
) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus}
select u1;
What about using Aggregate?
It's better than
Select max
Select by max value
since it only scans the array once.
var maxRow = table.Aggregate(
(a, b) => a.Status > b.Status ? a : b // whatever you need to compare
);
More one example:
Follow:
qryAux = (from q in qryAux where
q.OrdSeq == (from pp in Sessao.Query<NameTable>() where pp.FieldPk
== q.FieldPk select pp.OrdSeq).Max() select q);
Equals:
select t.* from nametable t where t.OrdSeq =
(select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)
Simply in one line:
var result = table.First(x => x.Status == table.Max(y => y.Status));
Notice that there are two action.
the inner action is for finding the max value,
the outer action is for get the desired object.

LINQ - SELECT DISTINCT with NOT IN

I'm have a SQL statement which I am trying to transform in a LINQ statement...
SELECT DISTINCT mc.*
FROM ManufractorCategories mc
WHERE mc.Active = 'true'
AND mc.Folder = 'false'
AND (mc.Id not in (SELECT Category_id FROM Manufractor_Category
WHERE Manufractor_id = 3));
That's my last, not working LINQ statement
(IQueryable<object>)db.ManufractorCategories
.Where(o => o.Active == active)
.Where(o => o.Folder == folder)
.Select(i => new { i.Id, i.Folder }).Except(db.Manufractor_Categories.Where(t => t.Manufractor_id == id).Select(t => new { t.Category_id })).Distinct();
I've tried the whole Sunday on that, but the Except statement won't work.
Thanks in advances for any help!
The Except method requires two sets of the same type - this means that you would have to select objects of type ManufractorCategory in the nested query as well as in the outer query - then it would select all categories that are in the first one and not in the second one.
An easier alternative is to use the Contains method to check whether the current ID is in a list of IDs that you want to filter. The following should work:
var q =
db.ManufractorCategories
.Where(o => o.Active == active)
.Where(o => o.Folder == folder)
.Select(i => new { i.Id, i.Folder })
.Where(o =>
!db.Manufractor_Categories
.Select(t => t.Manufractor_id)
.Contains(o.Id)
.Distinct();
And a simplified version using query syntax:
var q =
from o in db.ManufractorCategories
where o.Active == active && o.Folder == folder &&
db.Manufractor_Categories
.Select(t => t.Manufractor_id)
.Contains(o.Id)
select new { i.Id, i.Folder };
The Except statement is going to get a list of objects with the Category_id property. However, you're query has a result that contains objects with the Id and Folder properties. The query will most likely be unable to see where these objects are equal, and so, the Except clause won't take effect.

Categories