am stuck with this linq query, all i need is to optimize the last price calculation, cause i get about a 1000 article, & a lot of sales so its getting slow ...
var result = from article in db.Entities.Articles
select new{
article.ID_ART,
article.Designation,
article.BuyPrice,
article.SellPrice,
LastPrice = (from sale in article.Sales where sale.Date == article.Sales.Max(X => X.Date) select sale.Price).FirstOrDefault()==0?
article.BuyPrice: (from sale in article.Sales where sale.Date == article.Sales.Max(X => X.Date) select sale.Price).FirstOrDefault()
}
var result = from article in db.Entities.Articles
let lastPrice = (from sale in article.Sales
orderby sale.Date descending
select sale.Price).FirstOrDefault()
select new
{
article.ID_ART,
article.Designation,
article.BuyPrice,
article.SellPrice,
LastPrice = lastPrice ==0 ? article.BuyPrice : lastPrice
}
You should either join or Include Sales. I assume since it's a navigation property on article that it's an FK table.
Simply use from article in db.Entities.Articles.Include("Sales")... instead.
That will load sales for reference and prevent it from running a subquery when initializing the anonymous type.
Related
I am working on a system for handling meter reading.
I want to produce a output where the system displays all the meters belonging to the customer and for each meter, the three last readings.
So far, I have to followering code:
var lastMeterReading = from meeters in metermodel.Meeters
join reading in metermodel.Readings on meeters.MeterNumber equals reading.MeterNumber
where (maalers.CustNo == 6085574)
orderby reading.Date descending
group meeters by new { meeters.MeterNumber, reading.Consumption, reading.Date } into result
select new
{
Consumption = result.Key.Consumption, No = result.Key.MeterNumber, Date = result.Key.Date
};
Now, it shows all the meters belonging to the customer. If I put a .take(3), it only shows the first 3 results.
Thx!
Daniel
I think what you need is to put the .Take(3) in the right place.
In you case you probably did result.Take(3) but this means take the first three groups (with all their elements).
Below is an attempt to show what I mean, however, I suppose you will need to fix it in the last part, as I don't have data to test it on, and as such I'm not sure if what I'm trying to access is accessible at that point. But I hope you get what I mean.
var lastMeterReading = (from meeters in metermodel.Meeters
join reading in metermodel.Readings on meeters.MeterNumber equals reading.MeterNumber
where (maalers.CustNo == 6085574)
orderby reading.Date descending
group meeters by new { meeters.MeterNumber, reading.Consumption, reading.Date } into result
from m in result
select new {Key = m.Key, Info = result.OrderByDescending(r => r.Date).Take(3)})
.Select(r => new
{ Consumption = r.Consumption, No = r.MeterNumber, Date = r.Date });
Try this:
var lastMeterReading = from meeters in metermodel.Meeters
join reading in metermodel.Readings on meeters.MeterNumber equals reading.MeterNumber
where (maalers.CustNo == 6085574)
orderby reading.Date descending
group meeters by new { meeters.MeterNumber, reading.Consumption, reading.Date } into result
from m in result.Take(3)
select new
{
Consumption = m.Consumption, No = m.MeterNumber, Date = m.Date
};
You only want to group by MeterNumber. The way you're doing the grouping right now, you'll get a new group for every unique MeterNumber-Consumption-Date combination.
You can also simplify your query using LINQ's GroupJoin operator. In query syntax you use the "join..on..into" pattern:
from meter in meterModel.Meters
where (meter.CustNo == 6085574)
join reading in meterModel.Readings
on meter.MeterNumber equals reading.MeterNumber
into meterGroup
select meterGroup.OrderByDescending(r => r.Date).Take(3);
Or using dot notation:
meterModel.Meters
.Where(x => x.CustNo == 6085574)
.GroupJoin(
meterModel.Readings,
meter => meter.MeterNumber,
reading => reading.MeterNumber,
(meter,readings) => readings.OrderByDescending(r => r.Date).Take(3))
;
Example scenario:
Two tables: order and orderItem, relationship One to Many.
I want to select all orders that have at least one orderItem with price 100 and at least one orderItem with price 200.
I can do it like this:
var orders = (from o in kontextdbs.orders
join oi in kontextdbs.order_item on o.id equals oi.order_id
join oi2 in kontextdbs.order_item on o.id equals oi2.order_id
where oi.price == 100 && oi2.price == 200
select o).Distinct();
But what if those conditions are user generated?
So I dont know how many conditions there will be.
You need to loop through all the values using a Where and Any method like this:
List<int> values= new List() { 100, 200 };
var orders = from o in kontextdbs.orders
select o;
foreach(int value in values)
{
int tmpValue = value;
orders = orders.Where(x => kontextdbs.order_item.Where(oi => x.id == oi.order_id)
.Any(oi => oi.price == tmpValue));
}
orders = orders.Distinct();
List<int> orderValues = new List() { 100, 200 };
ObjectQuery<Order> orders = kontextdbs.Orders;
foreach(int value in orderValues) {
orders = (ObjectQuery<Order>)(from o in orders
join oi in kontextdbs.order_item
on o.id equals oi.order_id
where oi.price == value
select o);
}
orders = orders.Distinct();
ought to work, or at least that's the general pattern - you can apply extra queries to the IObjectQueryables at each stage.
Note that in my experience generating dynamic queries like this with EF gives terrible performance, unfortunately - it spends a few seconds compiling each one into SQL the first time it gets a specific pattern. If the number of order values is fairly stable though then this particular query ought to work OK.
I'm at the finish line for my university project, and I'm kinda stuck at finishing a query.
The working query looks like this:
var Report = from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
};
I would really appreciate it if you can show me, how to Order the results by the given "Quantity" in descending order.
Thanks!
var Report = (from query in Document.Descendants("order")
group query by query.Element("seller").Value into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
})
.OrderByDescending(order => order.Quantity);
Please do this :
var Report = (from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
select new Orders
{
Seller = qGroup.Key,
Quantity = qGroup.Sum(p => int.Parse(p.Element("quantity").Value)).ToString()
}).OrderByDescending(x => x.Quantity);
HTH !!!!
(Kudos to LINQ Orderby Descending Query )
The answers by Skippy and Andrei work, but you can also write as
var Report = from query in Document.Descendants("order")
group query by query.Element("seller").Value
into qGroup
let qty = qGroup.Sum(p =>int.Parse(p.Element("quantity").Value)).ToString()
orderby qty descending
select new Orders
{
Seller = qGroup.Key,
Quantity = qty
};
if you'd rather keep it all in one syntax.
I had tried to join two table conditionally but it is giving me syntax error. I tried to find solution in the net but i cannot find how to do conditional join with condition. The only other alternative is to get the value first from one table and make a query again.
I just want to confirm if there is any other way to do conditional join with linq.
Here is my code, I am trying to find all position that is equal or lower than me. Basically I want to get my peers and subordinates.
from e in entity.M_Employee
join p in entity.M_Position on e.PostionId >= p.PositionId
select p;
You can't do that with a LINQ joins - LINQ only supports equijoins. However, you can do this:
var query = from e in entity.M_Employee
from p in entity.M_Position
where e.PostionId >= p.PositionId
select p;
Or a slightly alternative but equivalent approach:
var query = entity.M_Employee
.SelectMany(e => entity.M_Position
.Where(p => e.PostionId >= p.PositionId));
Following:
from e in entity.M_Employee
from p in entity.M_Position.Where(p => e.PostionId >= p.PositionId)
select p;
will produce exactly the same SQL you are after (INNER JOIN Position P ON E..PostionId >= P.PositionId).
var currentDetails = from c in customers
group c by new { c.Name, c.Authed } into g
where g.Key.Authed == "True"
select g.OrderByDescending(t => t.EffectiveDate).First();
var currentAndUnauthorised = (from c in customers
join cd in currentDetails
on c.Name equals cd.Name
where c.EffectiveDate >= cd.EffectiveDate
select c).OrderBy(o => o.CoverId).ThenBy(o => o.EffectiveDate);
If you have a table of historic detail changes including authorisation status and effective date. The first query finds each customers current details and the second query adds all subsequent unauthorised detail changes in the table.
Hope this is helpful as it took me some time and help to get too.
Table 1: Lookups
LookUpID
LookUpName
Desc
DisplayOrder
Table 2: BillingRates
BillingRateID
BillingRate
ClientID
LookupID
I want the lookup name to be displayed (sort by Bill rate)
DataContext DataContext1 = new DataContext1(AppSettings.ConnectionString);
return ( from Lookups in DataContext1.Lookups
join BillingRates in DataContext1.BillingRates
on Lookups.LookupID equals BillingRates.LookupID
orderby BillingRates.BillingRate
select new
{
Lookups.LookupID,
Lookups.LookupName,
Lookups.Desc
}).Distinct();
It gave me all the row, so I used Distinct(); The lookup Name is still not based on billing rate.
I am new to LINQ. Any pointers would be appreciated.
Why not just do the OrderBy at the end?
return (from Lookups in DataContext1.Lookups
join BillingRates in DataContext1.BillingRates
on Lookups.LookupID equals BillingRates.LookupID
select new
{
Lookups.LookupID,
Lookups.LookupName,
Lookups.Desc,
BillingRates.BillingRate
})
.GroupBy(x => x.LookupID)
.Select(y => y.OrderByDescending(x => x.BillingRate).First())
.OrderByDescending(x => x.BillingRate);
EDIT: I am kind of confused but try the following and let me know if that helps.
First of all, if you have a foreign key relationship set up, LINQ will create the join for you automatically, so it would be just:
DataContext1.Lookups.Max(LkUp => LkUp.BillingRate.BillingRate)
Otherwise, (with the explicit join)
return ( from Lookups in DataContext1.Lookups
join BillingRates in DataContext1.BillingRates
on Lookups.LookupID equals BillingRates.LookupID
orderby BillingRates.BillingRate desc
select new
{
Lookups.LookupID,
Lookups.LookupName,
Lookups.Desc,
BillingRates.BillingRate
}).First();