Join Query C# SQL Server - c#

I'm developing on visual Studio using asp.net core and Entity Framework.
This is my query
var Male = from s in _context.ApprovalKits
join r in _context.Registrations on s.StundetId equals r.StundetId into a
where s.RoomType.Equals(RoomType.s)
&& s.HealthCondition.Equals(HealthCondition.none)
&& r.gender.Equals(Gender.m)
select a;
There is an error on the r.gender:
The name 'r' does not exist in the current context
How can I fix my query?

If your EF Entities have Associations set-up correctly then you should never need to use manual Joins in Linq because you can simply do this:
List<Registration> maleRegistrations = db.Registrations
.Include( r => r.ApprovalKit )
.Where( r => r.ApprovalKit.RoomType == RoomType.S )
.Where( r => r.HealthCondition == HealthCondition.None )
.Where( r => r.Gender == Gender.Male );
.ToList();
(You can also consolidate the Where, like so:)
List<Registration> maleRegistrations = db.Registrations
.Include( r => r.ApprovalKit )
.Where( r =>
r.ApprovalKit.RoomType == RoomType.S &&
r.HealthCondition == HealthCondition.None &&
r.Gender == Gender.Male
)
.ToList();

Related

Convert SQL Query to LINQ Lambda C#

I have to fix a query which was already written in the LINQ Lambda, I found the fix in a Simple SQL Query but now I have some trouble in converting it to LINQ Query,
Here is my SQL Query
select * from RequestItem_SubRequestItem x
where x.RequestItem_key = 1 and x.SubRequestItem_key in (
select o.SubRequestItem_key
from SubRequestItem_Entitlement o
inner join SubRequestItem sr on sr.SubRequestItem_key = o.SubRequestItem_key
where o.Entitlement_key = 2 and sr.Action = 'Add' )
And below is my LINQ C# code where I am trying to insert my fixes which include inner join.
z.Entitlements = ARMContext.Context.SubRequestItem_Entitlement
.Where(o => o.Entitlement_key == z.AccessKey && !o.Role_key.HasValue && o.Entitlement.EntitlementConfiguration.UserVisible == true
&& (ARMContext.Context.RequestItem_SubRequestItem
.Where(x => x.RequestItem_key == requestItemKey)
.Select(y => y.SubRequestItem_key)
.Contains(o.SubRequestItem_key)))
.Join(ARMContext.Context.SubRequestItems, subrq => subrq.SubRequestItem_key, temp => requestItemKey, (subrq, temp) => subrq == temp)
Where as previously the C# LINQ code looked like this
z.Entitlements = ARMContext.Context.SubRequestItem_Entitlement
.Where(o => o.Entitlement_key == z.AccessKey && !o.Role_key.HasValue && o.Entitlement.EntitlementConfiguration.UserVisible == true
&& (ARMContext.Context.RequestItem_SubRequestItem
.Where(x => x.RequestItem_key == requestItemKey)
.Select(y => y.SubRequestItem_key)
.Contains(o.SubRequestItem_key)))
When I try to insert the JOIN in the LINQ as per my conditions then I get to see this error.
What is my mistake? Can anybody tell me a correct way to do it?
I think this should Suffice your need, although you might have to make changes to the other code which are dependent on your SubRequestItem_Entitlement table with {user, add}
please have a look at that. As I am sure you will have to make those changes.
.Join(ARMContext.Context.SubRequestItems, user => user.SubRequestItem_key, subreqItems => subreqItems.SubRequestItem_key, (user, subreqItems) => new { user, subreqItems })
.Where(Action => Action.subreqItems.Action == z.ApprovalAction)
you can use this query. I exactly matched the SQL query
var query = ARMContext.Context.RequestItem_SubRequestItem
.Where(a => a.RequestItem_key == 1 && a.RequestItem_key == (ARMContext.Context.SubRequestItem_Entitlement
.Join(ARMContext.Context.SubRequestItems,
right => right.SubRequestItem_key,
left => left.SubRequestItem_key,
(right, left) => new
{
right = right,
left = left
})
.Where(x => x.right.Entitlement_key == 2 && x.left.Action == "Add" && x.right.SubRequestItem_key == a.RequestItem_key).Select(y => y.right.SubRequestItem_key)).FirstOrDefault());

Getting 2 Top 5 within a single LINQ query in EFCore

I want to load 10 latest products containing 5 of category A and 5 of category B.
So the result contains 5 latest products with category A and 5 latest products of category B.
Normally I can do it using these two:
var listA = await (
from p in db.Set<Product>()
where p.Category == "A"
orderby p.ProductDate descending
select p
).Take(5).ToListAsync();
var listB = await (
from p in db.Set<Product>()
where p.Category == "B"
orderby p.ProductDate descending
select p
).Take(5).ToListAsync();
var result = listA.Concat(listB);
But as you see this piece of code requires 2 calls to the database.
How can I get the result, using just 1 database call?
With EF Core 3.0.0-preview7.19362.6, you can write it like this which produces just a single query and works perfectly fine :
IQueryable<Product> topA = context.Products
.Where(p => p.Category == "A")
.OrderByDescending(x => x.ProductDate)
.Take(5);
IQueryable<Product> topB = context.Products
.Where(p => p.Category == "B")
.OrderByDescending(x => x.ProductDate)
.Take(5);
List<Product> result = await topA
.Concat(topB)
.OrderBy(p => p.Category)
.ToListAsync();
Use Concat before await
var listA = (
from p in db.Set<Product>()
where p.Category == "A"
orderby p.ProductDate descending
select p
).Take(5);
var listB = (
from p in db.Set<Product>()
where p.Category == "B"
orderby p.ProductDate descending
select p
).Take(5);
var result= await listA.Concat(listB).ToListAsync();
Recently, The EF team has confirmed that translation of UNION, CONCAT, EXCEPT, and INTERSECT is going to be added to EF Core 3.
So, If you are using EF Core 3 Preview then good luck otherwise you have to use RAW SQL queries if you want to go with one shot.
In LINQ Query something like this should work:
var list = await(db.Product.Where(p => p.Category == "A" || p.Category == "B").OrderByDescending(p => p.ProductDate)
.ToList()
.GroupBy(p => p.Category)
.SelectMany(t => t.Select(b => b).Zip(Enumerable.Range(0, 5), (j, i) => j))).ToListAsync();

OUTER APPLY is not supported in this LINQ query

I need to run this query in a oracle 11.2 database, but the generated query contains a "OUTER APPLY". How can I solve it ?
var query = from r in Ctx.Reg
let status_1 = (r.Hist.OrderByDescending(o => o.Id).FirstOrDefault(h => h.RegId == r.Id).Status == 1)
let status_2 = (r.Hist.OrderByDescending(o => o.Id).Skip(1).FirstOrDefault(h => h.RegId == r.Id).Status == 2)
select new
{
r.Id,
...
status_1,
status_2
};
OUTER APPLY is generated by your let statement expressions. You can avoid it by turning them into EXISTS translatable expressions using the equivalent Any based LINQ constructs:
var query = from r in Ctx.Reg
let status_1 = r.Hist.OrderByDescending(h => h.Id).Take(1).Any(h => h.Status == 1)
let status_2 = r.Hist.OrderByDescending(h => h.Id).Skip(1).Take(1).Any(h => h.Status == 2)
select new
{
r.Id,
...
status_1,
status_2
};
Note that h.RegId == r.Id is not needed because that is implied by r.Hist navigation property.

Select particular record if match is found otherwise First record in IGrouping<T>

Here is my LINQ query:
pmcPrices = (from pd in interfaceCtx.PmcPriceDatas
where
pd.ClientIdValue != null
&& pd.ClientIdCode == "FII"
&& (pd.MetricVal != null || pd.PMCPrice1 != null || pd.PMCPrice2 != null)
&& pd.EffectiveDate.Value == eodDate.DateTime
group pd by pd.ClientIdValue into g
select g).ToDictionary(g => Convert.ToInt32(g.Key),
g => g.SingleOrDefault(p => p.FeedCode == "EQRMS-CB"));
What I want to achieve is if any of the record in group 'g' has FeedCode == 'EQRMS-CB' select that record otherwise First record in group 'g'.
You could use a ternary operator
..
.ToDictionary(g => Convert.ToInt32(g.Key),
g => g.Any(p => p.FeedCode == "EQRMS-CB")
? g.First(p => p.FeedCode =="EQRMS-CB")
: g.First())
If it doesn't actually matter which you get if there is no match so long as you get one, or if you are using a Linq provider with a stable OrderBy (linq to objects and providers that make use of it is, most are not) then:
g => g.OrderBy(p => p.FeedCode != "EQRMS-CB").FirstOrDefault()
Otherwise:
g => g.FirstOrDefault(p => p.FeedCode == "EQRMS-CB") ?? g.FirstOrDefault()

Linq SQL join on same table with group and sum

I've had a look through StackOverflow and have tried things from a few posts but am totally stuck. Basically I have the query below (tested in LinqPad), which, for the "sum" values gives me the same value twice. What I actually want is a join to the same table, group by date and to show the sum of what is essentially the same column (Value), from the joined table and the original table.
I have found that you can't use aliases (i.e. in SQL FieldName as 'NewFieldName') in LINQ, so somehow I need to sum up t.Value and p.Value, and show those next to SiteID and EntryDate in my results.
(from p in DailyStatistics
join t in DailyStatistics on new { p.EntryDate, p.SiteID} equals new { t.EntryDate, t.SiteID}
where t.Metric == "MyVisitors"
&& p.Metric == "MyVisits"
&& p.EntryDate >= DateTime.Parse("2013-08-15" )
&& p.EntryDate <= DateTime.Parse("2013-08-21" )
group p by new { t.SiteID, p.EntryDate } into s
orderby s.Key.EntryDate
select new {s.Key.SiteID, s.Key.EntryDate, SumVisits = s.Sum(t => t.Value), SumVisitors = s.Sum(x => x.Value) })
This one in particular I tried, but couldn't quite adapt it to my needs:
SQL multiple joins and sums on same table
Any ideas would be happily accepted :-)
Edit
I forgot the where clause.
DailyStatistics
.Join
(
DailyStatistics,
x=>new{x.EntryDate, x.SiteID},
x=>new{x.EntryDate, x.SiteID},
(o,i)=>new
{
VisitorEntry=i.Metric,
VisitEntry=o.Metric,
VisitorDate = i.EntryDate ,
VisitDate = o.EntryDate ,
i.SiteID,
VisitorValue = i.Value,
VisitValue = o.Value
}
)
.GroupBy
(
x=>
new
{
x.SiteID,
x.VisitDate
}
)
.Where
(
x=>
x.VisitorEntry == "MyVisitors" &&
x.VisitEntry== "MyVisits" &&
x.VisitDate >= DateTime.Parse("2013-08-15") &&
x.VisitDate <= DateTime.Parse("2013-08-21")
)
.Select
(
x=>
new
{
x.Key.SiteID,
x.Key.VisitDate,
SumVisits = s.Sum(t => t.VisitValue ),
SumVisitors = s.Sum(x => x.VisitorValue )
}
)
.OrderBy
(
x=>x.VisitDate
)

Categories