Need To Convert SQL To LINQ - linq

Hi Stack i want to convert this to LINQ without any grouping in linq .
DB NorthWIND.
select
SUM(UnitsInStock)UnitsInStock,
SUM(UnitsOnOrder)UnitsOnOrder,
AVG(UnitPrice) AVGUnitPrice
from Products

This will do the trick:
var query=from p in db.Products
group p by 1 into g
select new
{
SumUnitsInStock= g.Sum(a => a.UnitsInStock),
SumUnitsOnOrder= g.Sum(a => a.UnitsOnOrder),
AvgUnitPrice= g.Average(a => a.UnitPrice)
};

Related

EF core Linq groupby and having sum count - could not be translated and will be evaluated locally

Following .net core EF core, Linq cannot be translated and will be evaluated locally. Can you please give me an advise?
var temp1= (from so in context.OrderShippingOrders
group so by so.OrderId into g
where g.Count(x=> x.IsSent == true ) == g.Count()
select new {
g.Key
}
);
query = (from o in context.Orders
join s in temp1
on o.Id equals s.Key
select o
);
The LINQ expression 'join AnonymousObject _o in {from Order o in value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1[ECommerce.API.Models.Order]) where ([o].ShopId == __queryObj_ShopId_Value_0) join <>f__AnonymousType181 s in {from IGrouping2 g in {from OrderShippingOrder so in value(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1[ECommerce.API.Models.OrderShippingOrder]) orderby [so].OrderId asc, [so].OrderId asc select [so] => GroupBy([so].OrderId, [so])} where ({from OrderShippingOrder x in [g] where ([x].IsSent == True) select [x] => Count()} == {[g] => Count()}) select new <>f__AnonymousType181(Key = [g].Key)} on [o].Id equals [s].Key orderby EF.Property(?[o]?, "Id") asc select new AnonymousObject(new [] {Convert(EF.Property(?[o]?, "Id"), Object)}) => Skip(__p_1) => Take(__p_2) => Distinct()} on Property([o.OrderDetails], "OrderId") equals Convert([_o].GetValue(0), Nullable1)' could not be translated and will be evaluated locally.
If possible, upgrade to EF Core 2.1 (or 2.2) in order to get improved LINQ GroupBy translation.
Before version 2.1, in EF Core the GroupBy LINQ operator would always be evaluated in memory. We now support translating it to the SQL GROUP BY clause in most common cases.
There is nothing you can do in previous EF Core versions.
After upgrading, in order to get SQL transation, the GroupBy query must be modified to use intermediate projection and conditional Sum instead of conditional Count like this:
var temp1 = (from so in context.OrderShippingOrders
group new { SendCount = so.IsSent ? 1 : 0 } by so.OrderId into g
where g.Sum(x => x.SendCount) == g.Count()
select new
{
g.Key
}
);
(unfortunately the more natual group so and g.Sum(x => x.IsSent ? 1 : 0) does not translate, that's why we need the group new { SendCount = so.IsSent ? 1 : 0 } and g.Sum(x => x.SendCount))
P.S. In case you have collection navigation property from Order to OrderShippingOrder (something like public ICollection<OrderShippingOrder> Shipping { get; set; }), then you can avoid all these GroupBy complications and use simply:
var query = context.Orders
.Where(o => o.Shipping.Count(so => so.IsSent) == o.Shipping.Count());

How do I outer join and group by in Entity framework Linq?

I'm having trouble getting my Linq statemnt to work when doing an outer join and a group by. Here's a SQL version of what I'm trying to accomplish:
select p.PRIMARY_KEY, min(p.EFFECTIVE_DATE), sum(IsNull(c.PAID_INDEMNITY, 0))
from PRMPOLCY p
left outer join CLMMAST c on p.PRIMARY_KEY = c.POLICY_NO
where p.UNDERWRITER_UID = 93
GROUP BY p.PRIMARY_KEY
Here's what I have in Linq (which doesn't work):
var result = from p in context.PRMPOLCies
join c in context.CLMMASTs on p.PRIMARY_KEY equals c.POLICY_NO into polClm
where (p.UNDERWRITER_UID == underwriter)
from grp in polClm.DefaultIfEmpty()
group grp by p.PRIMARY_KEY into g
select new PolicySummation()
{
PolicyNo = g.Key,
Incurred = g.Sum(grp => grp.PAID_INDEMNITY ),
EffDate = g.Min(grp => grp.PRMPOLCY.EFFECTIVE_DATE
};
Beating my head against the wall trying to figurwe this out!
Assuming you have a navigation property set up between PRMPOLCY and CLMMAST, you shouldn't need to specify the join explicitly. It's much easier to express most queries in linq without explicit joins, but rather treating your structures as a hierarchy. I don't know the specifics of your model property names, but I'd take a guess that something like this would work.
var result =
from p in context.PRMPOLCies
where (p.UNDERWRITER_UID == underwriter)
select new PolicySummation {
PolicyNo = p.PRIMARY_KEY,
Incurred = p.CLMASTs.Select(c => c.PAID_INDEMNITY).DefaultIfEmpty().Sum(),
EffDate = p.EFFECTIVE_DATE,
};
You need to include both your tables in the group clause like this:
group new { p, grp } by p.PRIMARY_KEY into g
Then in your Sum / Min
g.Sum(grp => grp.grp == null ? 0 : grp.grp.PAID_INDEMNITY )
g.Min(grp => grp.p.PRMPOLCY.EFFECTIVE_DATE)

Get data from multiple tables to an object with LINQ join

I am trying to get from 3 related tables by using LINQ. But when I use 2 joins, the result takes only elements getting from 2nd join. Here is my code:
var myAssList = mldb.Assigns
.Join(mldb.Lists,
a => a.list_id,
l => l.id,
(a, l) => new {
Assign = a,
List = l
})
.Where(a => a.Assign.assigned_to == "myname")
.Join(mldb.Elements,
li => li.List.id,
e => e.parent_server_id,
(li, e) => new {
Element = e
});
var jsonSerialiser = new JavaScriptSerializer();
var listListJson = jsonSerialiser.Serialize(myAssList);
this Json return only attributes from Element(e) and List(li). But I want to get also the attributes from Assign(a).
The SQL query I am trying to realize in LINQ is that:
select * from Assigns
inner join Lists
on Assigns.server_list_id=Lists.id
inner join Elements
on Lists.id=Elements.parent_id
where Assigns.assigned_to='myname'
So, how can I get the attributes from the first join also (from "a", "l" and "e")?
You can access Assign entity from outer sequence li variable:
.Join(mldb.Elements,
li => li.List.id,
e => e.parent_server_id,
(li, e) => new {
Element = e,
Assign = li.Assign // here
});
from a in mldb.Assigns
join l in mldb.Lists on a.list_id equals l.id
join e in mldb.Elements on l.id equals e.parent_server_id
where a => a.Assign.assigned_to == "myname"
select new { Assign = a, Element = e }
This is so called "query syntax". It makes LINQ expressions looks like SQL queries.
In the end they are translated to IEnumerable extension methods. If you want
to join multiple tables then query syntax is more readable. Another useful feature
of query syntax is let clause. With the aid of it, you can declare additional variables
inside your queries.

Many to Many EF LINQ

I have a database that has the following tables:
dbo.Administrator
dbo.Application
dbo.AdminApplication
dbo.Proficiency
dbo.ProficiencyLevel
Administrators contain 1 to many Applications. Application contains many administrators
Applications contain 1 to many Proficiency(s)
Proficiency contains 1 to many ProficiencyLevels
Using EF Code First, the AdminApplication is not mapped as an entity and this is what is causing me issues. What I want to answer is the following:
"Return all the ProficiencyLevels of the Administrator named "danhickman".
In SQL, the query would look like this:
Select * from dbo.ProficiencyLevel pl
inner join dbo.Proficiency p on p.Id = pl.ProficiencyId
inner join dbo.Application a on a.Id = p.ApplicationId
inner join dbo.AdminApplication aa on aa.ApplicationId = a.Id
inner join dbo.Administrator ad on ad.Id = aa.AdministratorId
where ad.Name = 'danhickman'
I solved this with the following C# code:
public IQueryable<LobGame.Model.ProficiencyLevel> GetAllByAdminName(string administratorName)
{
var context = this.DbContext as LobGameDbContext;
var admin = context.Administrators.Include(i => i.Applications).Include("Applications.Proficiencies").Include("Applications.Proficiencies.ProficiencyLevels").Single(o => o.Name == administratorName);
List<LobGame.Model.ProficiencyLevel> list = new List<ProficiencyLevel>();
foreach (var app in admin.Applications)
{
foreach (var prof in app.Proficiencies)
{
list.AddRange(prof.ProficiencyLevels);
}
}
return list.AsQueryable();
}
It bugs me that I have to foreach and add to a list. I was unable to figure out a way to do this in a single LINQ statement. any thoughts?
Another option using query syntax. This uses SelectMany under the covers.
var queryableList =
from admin in context.Administrators
where admin.Name = administratorName
from app in admin.Applications
from proficiency in app.Proficiencies
from level in proficiency.ProficiencyLevels
select level;
Note: this will be an IQueryable, so you don't need the .ToList().AsQueryable().
return context.Administrators
.Single(o => o.Name == administratorName)
.Applications
.SelectMany(app => app.Proficiencies)
.SelectMany(prof => prof.ProficiencyLevels)
.ToList()
.AsQueryable();
Use SelectMany():
var queryableList =
context.Administrators.Single(o => o.Name.Equals(administratorName))
.SelectMany(adm => adm.Applications.Select(app => app.Proficiencies.SelectMany(prof => prof.ProficiencyLevels))).ToList().AsQueryable();

Linq expression for left join and filter for the inner table

I want to know how to make Linq expression that has the same effect as these SQL query
SELECT item.*, priceforitem.*
FROM
item
LEFT JOIN priceforitem
ON priceforitem.ItemID = item.ItemID
AND priceforitem.PriceID = ?PriceID
I already make it using the Method query but I don't know if it will produce the same result
db.Items
.GroupJoin(
db.PriceForItems.Where(pi => pi.PriceID == id),
i => i.ItemID,
pi => pi.ItemID,
(i, pi) => new { Item = b, Prices = pi })
.SelectMany(
a => a.Prices.DefaultIfEmpty(),
(i, pi) => new
{
ItemID = i.Item.ItemID,
Code = i.Item.Code,
Name = i.Item.Name,
PriceForItemID = pi.PriceForItemID,
Price = pi.Price
})
and then after thinking for awhile i shorten it like this
db.Items
.SelectMany(
i => db.PriceForItems.Where(
pi => pi.PriceID == id
&& pi.ItemID = i.ItemID).DefaultIfEmpty(),
(i, pi) => new
{
ItemID = i.Item.ItemID,
Code = i.Item.Code,
Name = i.Item.Name,
PriceForItemID = pi.PriceForItemID,
Price = pi.Price
})
I am new to Linq, and I don't know which is better and how to convert it to Linq query statement.
First of all your sql query. It is effectively and inner join because the where condition will filter out all rows where data from priceforitem is null. If you do want to convert same query to linq you can do it like
from i in db.Items
join p in db.PriceforItems on
i.ItemId equals p.ItemId into tempvals
from t in tempvals.DefaultIfEmpty()
where t.PriceId == id
select new{i.ItemId, ..., t.PriceId, t...., t....}
I mostly write linq queries instead of expressions where they are more readable to me. If you still want to get an expression, you can write a valid linq query and paste it into Linqpad and it will give the result as well as lambda expression of your query.

Resources