I have a query like this
SELECT id
FROM params
WHERE valid=1
AND id NOT IN (SELECT pid
FROM clientparams
WHERE update = 0 AND client=15)
LIMIT 25
I am trying to convert it to entity framework equivalent:
IQueryable<Params> parame = db.Params.Where(p => p.valid.Equals(1)).Except(....);
But I am stuck at the point where I need to make an equivalent for the subquery
Any ideas how to solve it?
Try this
IQueryable<Params> parame = db.Params.Where(p => p.valid.Equals(1) &&
!db.clientParams.Any(e => e.pid == p.id && e.update == 0 && e.client == 15))
.OrderBy(e => e.id) //Order by any field.
.Take(25);
Related
I'm trying to convert this SQL Query into Core EF:
SELECT w.IdShippingBatch, w.BookingNumber, COUNT(c.IdShippingOrder) AS ShippingOrders, w.CreatedOn, w.ModifiedOn
FROM dbo.Shipping`enter code here`Batch AS w LEFT OUTER JOIN
dbo.ShippingOrders AS c ON w.IdShippingBatch = c.IdShippingBatch
WHERE (w.IdCompany = 2) AND (w.IdDealer = 1)
GROUP BY w.IdShippingBatch, w.BookingNumber, w.CreatedOn, w.ModifiedOn
I have tried multiple solutions, including several here. My latest attempt looks like:
var data = (from w in _context.ShippingBatch
join c in _context.ShippingOrders on w.IdShippingBatch equals c.IdShippingBatch into t1
where w.IdCompany == idCompany && w.IdDealer == idDealer
from t2 in t1.DefaultIfEmpty()
group t2 by new { w.IdShippingBatch, w.BookingNumber, w.CreatedOn, w.ModifiedOn } into t3
select new ShippingBatchDTO
{
IdShippingBatch = t3.Key.IdShippingBatch,
BookingNumber = t3.Key.BookingNumber,
ShippingOrders = t3.Count(),
CreatedOn = t3.Key.CreatedOn,
ModifiedOn = t3.Key.ModifiedOn
});
I have also tried adding t3.count(m => m.something != null), but that throws an error.
One major point of EF is to map the relationship between entities so that you can leverage LINQ and let EF compose an SQL query rather than trying to replace SQL with LINQ-QL.
If your ShippingBatch is mapped with a collection of ShippingOrders...
var batches = _context.ShippingBatch
.Where(x => x.IdCompany == idCompany && x.IdDealer == idDealer)
.Select(x => new ShippingBatchDTO
{
IdShippingBatch = x.IdShippingBatch,
BookingNumber = x.BookingNumber,
ShippingOrders = x.ShippingOrders.Count(),
CreatedOn = x.CreatedOn,
ModifiedOn = x.ModifiedOn
}).ToList();
If your ShippingBatch does not have a collection of ShippingOrders, but your ShippingOrder reference an optional ShippingBatch.
var batches = _context.ShippingOrder
.Where(x => x.ShippingBatch != null
&& x.ShippingBatch.IdCompany == idCompany
&& x.ShippingBatch.IdDealer == idDealer)
.GroupBy(x => x.ShippingBatch)
.Select(x => new ShippingBatchDTO
{
IdShippingBatch = x.Key.IdShippingBatch,
BookingNumber = x.Key.BookingNumber,
ShippingOrders = x.Count(),
CreatedOn = x.Key.CreatedOn,
ModifiedOn = x.Key.ModifiedOn
}).ToList();
That should hopefully get you moving in the right direction. If not, expand your question to include details of what you are seeing, and what you expect to see along with definitions for the applicable entities.
I have this situation:
I have a form in ASP.NET and I need to extract data from a mssql db. The LINQ query is build from the values that are inserted in the form.
if (ddlRegion.SelectedIndex > 0)
{
query = query.Where(re => re.Region == ddlRegion.SelectedValue);
}
if (tbName.Text.Trim().Length > 0)
{
query = query.Where(na => na.Name.Contains(tbName.Text));
}
var result = query.Select(res => new
{
res.ColumnA,
res.ColumnB,
res.ColumnC
});
The problem is that I need to make a join with TableB
query = query.Join(TableB, tA => tA.Code, tB => tB.CodFiscal, (tA, tB) => tA);
The original SQL command is like this:
select tA.ColumnA, tA.ColumnB, tA.ColumnC from TableA tA join TableB tB on tA.Code=tB.Code where tB.ExpireDate>=getdate() and tB.datavalabil >=getdate()
The problem is where clauses from table tB join.
You can do something like this:
query = query.Join(TableB, tA => tA.Code, tB => tB.CodFiscal, (tA, tB) => new { tA, tB })
.Where(x => x.tB.ExpireDate >= DateTime.Now and x.tB.datavalabil >= DateTime.Now)
.Select(x => x.tA);
Or in query syntax:
query =
from tA in query
join tB in TableB on tA.Code equals tB.CodFiscal
where tB.ExpireDate >= DateTime.Now and tB.datavalabil >= DateTime.Now
select tA;
Afternoon,
How would i set this as not equal to? I am basically trying to say, if p.catrgory is not equal to one of the categories in the database.
p.category == dc.Categories.SingleOrDefault(c => c.Name == p.category).Name
Thanks in advance
p.Category is not in the DB?
var exists == !dc.Categories.Any(c => c.Name == p.category)
dc.Categories.Where(c => c.Name = p.category).Any();
it will return true if exists, so, use, ! operator
!dc.Categories.Where(c => c.Name = p.category).Any();
You should change:
p.category == dc.Categories.SingleOrDefault(c => c.Name == p.category).Name
to
p.category == dc.Categories.SingleOrDefault(c => c.Name != p.category).Name
if p.category is not equal to one of the categories in the databas
I want to build dynamic Linq. Following is my code which works fine for one date. But user can select many dates from calendar. And I need to make Linq for all those selected dates.
saleDate = calendarSales.SelectedDate;
List<SaleDetails> saleDetials = new List<SaleDetails>();
saleDetials = GetSaleDetails();
saleDetials.Where(sale => (Convert.ToDateTime(sale.DATE_TIME).Day == saleDate.Day &&
Convert.ToDateTime(sale.DATE_TIME).Month == saleDate.Month &&
Convert.ToDateTime(sale.DATE_TIME).Year == saleDate.Year)
).ToList();
How to update this query?
You have to build the predicate for your where clause dynamically.
Take a look at the predicatebuilder.
EDIT
Of cause PredicateBuilder supports AND and OR operators.
When using OR you have to start with the initial value of False:
// building the predicate
var pred = PredicateBuilder.False<SaleDetails>();
foreach (var date in MyDateList)
{
pred = pred.Or(sale => sale.DATE_TIME.Date == saleDate.Date);
}
// finally get the data and filter it by our dynamic predicate
List<SaleDetails> saleDetails = GetSaleDetails().Where(pred).ToList();
I'm not sure you need dynamic LINQ here. You should be able to check Where the sale matches Any of the selected dates, like so:
var saleDates = GetSelectedDate();
List<SaleDetails> saleDetials = new List<SaleDetails>();
saleDetials = GetSaleDetails();
saleDetials.Where(sale => saleDates.Any(date =>
(Convert.ToDateTime(sale.DATE_TIME).Day == date.Day &&
Convert.ToDateTime(sale.DATE_TIME).Month == date.Month &&
Convert.ToDateTime(sale.DATE_TIME).Year == date.Year)
)).ToList();
or checking on the Date property:
var saleDates = GetSelectedDate();
List<SaleDetails> saleDetials = new List<SaleDetails>();
saleDetials = GetSaleDetails();
saleDetials.Where(sale => saleDates.Any(date =>
Convert.ToDateTime(sale.DATE_TIME).Date == date.Date)).ToList();
That is the most efficient way to perform a left outer join in LINQ if I must do the following...
Filter Table 2 by a beginning and ending date.
All rows in Table 1 must remain, even if the filtering of Table 2 returns no rows.
The result must be grouped so that the columns from Table 2 get summed.
For example (example code variable names changed for propietary reasons), supposed I have a database with two tables. Table 1 has a list of doors with a building code, door ID and current status (open or closed) - the building code and door ID are the primary key. Table 2 has a list of events for all doors (an event is an opening or closing) plus a timestamp. So the columns are building code, door ID, timestamp, opening, closing. Opening and closing are integers with a 1 in the column for the appropriate event. There is a foreign key relationship between the two tables on the building code and door ID.
For my query I need to return a list of all the unique doors with the current door status and a sum of all the opening and closing events for a selected time period. An entry must be returned for each door, even if no events occured during the selected time period.
Below is the best LINQ code I could come up with. It works, but it seems really inefficient and hard to understand. How would you make it more efficient and easier to understand?
var query =
from doors in Context.Doors
join fevents in
(
from events in db.Events
where events.TimeStamp >= date1 && events.TimeStamp <= date2
select new { events.BuildingCode, events.DoorID, events.TimeStamp, events.Opening, events.Closing }
)
on new { doors.BuildingCode, doors.DoorID } equals { fevents.BuildingCode, fevents.DoorID }
into g1
from c in g1.DefaultIfEmpty()
group c by new
{
doors.BuildingCode,
doors.DoorID,
doors.DoorStatus
} into g2
select new
{
BuildingCode = g2.Key.BuildingCode,
DoorID = g2.Key.DoorID,
Status = g2.Key.DoorStatus
NumOpenings = g2.Sum(i => (i == null ? 0 : i.Opening)),
NumClosings = g2.Sum(i => (i == null ? 0 : i.Closing))
};
I think this is slightly easier to read
var query =
from doors in Context.Doors
from c in db.Events
.Where(events => doors.BuildingCode == events.BuildingCode)
.Where(events => doors.DoorID == events.DoorID)
.Where(events => events.TimeStamp >= date1 && events.TimeStamp <= date2)
.Select(events => new { events.BuildingCode, events.DoorID, events.TimeStamp, events.Opening, events.Closing })
.DefaultIfEmpty()
group c by new
{
doors.BuildingCode,
doors.DoorID,
doors.DoorStatus
} into g2
select new
{
BuildingCode = g2.Key.BuildingCode,
DoorID = g2.Key.DoorID,
Status = g2.Key.DoorStatus
NumOpenings = g2.Sum(i => (i == null ? 0 : i.Opening)),
NumClosings = g2.Sum(i => (i == null ? 0 : i.Closing))
};
The answer from #adducci helped me come up with a slightly different solution that I think is even more readable, albeit possibly less efficient.
var query =
from doors in Context.Doors
from events in doors.Events
.Where(i => i.TimeStamp >= date1 && i.TimeStamp <= date2)
.DefaultIfEmpty()
group new { doors, events }
by doors into g
select new
{
BuildingCode = g.Key.BuildingCode,
DoorID = g.Key.DoorID,
Status = g.Key.DoorStatus,
NumOpenings = g.Sum(i => (i.events == null ? 0 : i.events.Opening)),
NumClosings = g.Sum(i => (i.events == null ? 0 : i.events.Closing))
};
Note that an alternative method for filtering by date would be directly in the summing function, as below, but this is much less efficient since all records would be retrieved from the database and then filtered locally.
...
//from events in doors.Events
// .Where(i => i.TimeStamp >= date1 && i.TimeStamp <= date2)
// .DefaultIfEmpty()
from events in doors.Events
.DefaultIfEmpty()
...
NumOpenings = g.Sum(i => (i.events == null ? 0 : (i.events.Timestamp >= date1 && i.events.TimeStamp <= date2) ? i.events.Opening : 0)),
NumClosings = g.Sum(i => (i.events == null ? 0 : (i.events.Timestamp >= date1 && i.events.TimeStamp <= date2) ? i.events.Closing : 0))
...