LINQ Sub Query In Result Entity Framework 5 - c#

I've the following class
public class Interview
{
public int Id { get; set; }
public ICollection<InterviewSlot> Slots { get; set; }
}
public class InterviewSlots
{
public int Id { get; set; }
public Candidate Candidate { get; set; }
}
public class Candidate
{
public int Id { get; set; }
}
I want something like this,
var candidates = _DbContext.Interviews.Where(i => i.Id == Id).Select(s => s.Slots.Select(c => c.Candidate).ToList();
I don't want to use the InterviewSlots or the Candidate object
I want to get all the Candidates in a interview.
What would the LINQ be for this??

I'm thinking it may be along the lines of something like this in linq:
var candidates = _DbContext.Interviews.Where(i => i.Id == id)
.SelectMany(interview => interview.Slots)
.Select(slot => slot.Candidate)
.ToList();
tho, without seeing exactly how you plan to use it, quite a tricky one to answer.

I don't really understand your question
What would the LINQ be for this??
But here's what you need in order to get all candidates in an interview.
Without null checking.
var interview = _DbContext.Interviews.Where(i => i.Id == Id).Single();
var candidates = interview.Slots.Select(s => s.Candidate);
With null checking
var interview = _DbContext.Interviews.Where(i => i.Id == Id).SingleOrDefault();
if (interview != null)
var candidates = interview.Slots.Select(s => s.Candidate);
In one line
_DbContext.Interviews.Where(i => i.Id == Id)
.Single()
.Slots.Select(s => s.Candidate);

Related

How to convert SQL subquery to linq lambda?

I have following SQL subqueries and want to convert them to linq lambda.
Count:
select count(*)
from ParentA
where orderStatus in ('Status1','Status2')
and orderNumer in (select orderNumber
from ChildB
where approval = 0)
Entities:
public class ParentA
{
public long ProductID { get; set; }
public string ProductName { get; set; }
public ChildB Order { get; set; }
public string orderStatus { get; set; }
public long orderNumer { get; set; }
}
public class ChildB
{
public long Id { get; set; }
public string Name { get; set; }
public long orderNumer { get; set; }
public bool approval { get; set;}
}
All columns:
select *
from ParentA
where orderStatus = 'Status1'
and orderNumer in (select orderNumber
from ChildB
where approval = 1)
Eg:
var query =_dbcontext.ParentA.Include().Where().Count();
After looking at your posted classes, it looks more like ChildB is the parent and ParentA is the child, with one ChildB per ParentA.
The following should be the method LINQ equivalents:
var result1 = db.ParentA
.Where(a =>
(a.orderStatus == "Status1" || a.orderStatus == "Status2")
&& !a.ChildB.approval
)
.Count();
var result2 = db.ParentA
.Where(a =>
(a.orderStatus == "Status1")
&& a.ChildB.approval
)
.ToList();
If you ChildB class has a ParentA collection not shown in your post, this could also be written as:
var result1 = db.ChildB
.Where(b => !b.approval)
.SelectMany(b => b.ParentA
.Where(a => a.orderStatus == "Status1" || a.orderStatus == "Status2")
)
.Distinct()
.Count();
var result2 = db.ChildB
.Where(b => b.approval)
.SelectMany(b => b.ParentA
.Where(a => a.orderStatus == "Status1")
)
.Distinct()
.ToList();
Here's a rough take of what you're looking for.
// Create a collection of some form with your statuses you want to check.
var statuses = new string[] {"Status1", "Status2"};
// Get your order numbers for the 'orderNumber in' portion of your query.
var orderNumbers = _dbcontext.ChildB.Where(x => x.approval == 0);
// Get the count using these collections.
var count = _dbcontext.ParentA.Where(x => statuses.Contains(x.orderStatus) && orderNumbers.Contains(x.orderNumber)).Count();
// Your 'All columns' query is slightly simpler, if you know you only need to filter by the one status instead of multiple...
var approvedOrderNumbers = _dbcontext.ChildB.Where(x => x.approval == 1);
var results = _dbcontext.ParentA.Where(x => x.orderStatus == "Status1" && approvedOrderNumbers.Contains(x.OrderNumber)).ToList();
Some things to note:
If you have a navigation property between ParentA and ChildB (which any properly designed database/DbContext should have, the LINQ would look different.
LINQ is always a little backwards from how SQL does in. As you can see, first you must build the collection you want to use for your in parameter, and then see if it contains the entity value.
I wrote this code freehand in a text editor, and I never use string arrays so I'm not even sure if that's the proper syntax to initialize one.
Based on the confirmation that you have navigation properties on ParentA, here's an example of how to use those:
var statuses = new string[] {"Status1", "Status2"};
var count = _dbcontext.ParentA.Where(x => statuses.Contains(x.orderStatus) && x.ChildBs.Any(y => y.approval == 0)).Count();
var results = _dbcontext.ParentA.Where(x => x.orderStatus == "Status1" && x.ChildBs.Any(y => y.approval == 1)).ToList();
Some additional notes:
If you were to share your actual goal, such as "Get the count of all the ParentAs where all of their ChildBs are approved," or, "Get all the columns from ParentA where any of their ChildBs are not approved," would allow us to better help you in writing the correct statements.
As it stands, these queries will get you:
A set of ParentA that contain at least one ChildB with approval of 0.
A set of ParentA that contain at least one ChildB with approval of 1.
If that's not what you want, then you need to include in plain English what your result set should look like.

How to use Linq to select desired data

I have the following model:
public class EventList
{
Event[] Events {get; set;}
}
public class Event
{
EventType Type {get; set;}
Guid Id {get; set;}
IEnumerable<Accounts>? Accounts { get; set; }
IEnumerable<MetaData>? Metadata { get; set; }
IEnumerable<Roles>? Roles { get; set; }
}
Now, I would like to get the data that has EventType.Added, and also only want those events that regards roles with the Id of 42.
I have done this to sort only get them that has the EventType.Added:
var addedIdentities = eventList.Events.Where(x => x.EventType == IdentityEventType.AddedIdentity);
Now I would like to sort this even further, by only get the data that belongs to events with roleId 42:
var identitiesByRoles = addedIdentities.Where(x => x.Roles.Where(y => y.RoleId == 42));
This clearly don't work, and I don't really know how to solve this in Linq in a nice way?
Any suggestions?
Try this:
var identitiesByRoles = addedIdentities.Where(x => x.Roles.Any(y => y.RoleId == 42));
Or, if x.Roles could be null:
var identitiesByRoles = addedIdentities.Where(x => x.Roles?.Any(y => y.RoleId == 42) == true);
And combining with the other .Where:
var addedIdentities = eventList.Events
.Where(x => x.EventType == IdentityEventType.AddedIdentity)
.Where(x => x.Roles?.Any(y => y.RoleId == 42) == true);

Filter on nested object in LINQ

I have the following query in LINQ to return a policy object with a list of its policy risks, and within the policy risk a list of its transaction movements.
corePolicy = _db.Policies
.OrderByDescending(p => p.BatchId)
.Include(policy => policy.PolicyRisks.Select(policyRisks =>
policyRisks.TransactionMovements))
.Include(policy => policy.PolicyRisks.Select(policyRisks =>
policyRisks.PolicyRiskClaims.Select(prc =>
prc.TransactionMovements)))
.AsNoTracking()
.First(p =>
p.PolicyReference == policyFromStaging.PolicyReference &&
p.PolicySourceSystemId == policyFromStaging.PolicySourceSystemId);
How do I apply a .Where() clause to the transaction movements, say TransactionReference == 'ABC'
Below is my data model
[Table("business.Policy")]
public class Policy
{
[Required, StringLength(50)]
public string PolicyReference { get; set; }
public int PolicySourceSystemId { get; set; }
public System PolicySourceSystem { get; set; }
}
[Table("business.PolicyRisk")]
public class PolicyRisk
{
public ICollection<TransactionMovement> TransactionMovements { get; set; }
}
[Table("business.TransactionMovement")]
public class TransactionMovements
{
public string TransactionReference { get; set; }
}
Having Where statement in Include is not possible. You can have Any something like below:
corePolicy = _db.Policies
.OrderByDescending(p => p.BatchId)
.Include(policy => policy.PolicyRisks.Select(policyRisks =>
policyRisks.TransactionMovements))
.Include(policy => policy.PolicyRisks.Select(policyRisks =>
policyRisks.PolicyRiskClaims.Select(prc =>
prc.TransactionMovements)))
.AsNoTracking()
.Where(p => p.PolicyRisks.Any(pr => pr.PolicyRiskClaims.Any(prc => prc.TransactionMovements.Any(tm => tm.TransactionReference == 'ABC'))))
.First(p =>
p.PolicyReference == policyFromStaging.PolicyReference &&
p.PolicySourceSystemId == policyFromStaging.PolicySourceSystemId);
This will include policies if any of the transaction reference is ABC (on its child collections). So, again you have to have a looping mechanism in c# side to get the policy which have this TransactionReference.
If you want to avoid having loop, then I would suggest writing your linq from other end meaning, start from TransactionMovement and go back to Policy.
You can have WHERE clause in Include filter with some third party library as mentioned here.

c# Linq Get the ids of list elements in the entity query

Can i find an entity in a single query and attract the ids in this list?
Entities
public class Blog : IEntity
{
public int Id { get; set; }
public virtual IList<Category> Categories { get; set; } = new List<Category>();
}
public class Category : IEntity
{
public int Id { get; set; }
public virtual IList<Blog> Blogs { get; set; } = new List<Blog>();
}
Can I make the following code in one query? It should be find both blog and category ids.
var blog = _blogService.Queryable().Include(x => x.Categories).FirstOrDefault(x => x.Id == id);
_blogService.DisposeContext();
var categoryIds = blog?.Categories.Select(x => x.Id).ToList();
Assuming the Queryable() is Queryable<Blog>, you should be able to use the following:
_blogService
.Queryable()
.Include(x => x.Categories)
.Where(x => x.Id == id)
.Select(x => x.Categories.Select(c => c.Id))
.FirstOrDefault();
_blogService.Blogs.Where(b => b.Id == blogId).Include(b => b.Categories) should do the trick. No need to call the categories again.
For details about eager loading check this link

How to convert this LINQ to Entities query into 'Method Syntax' instead of 'Query Syntax'

I have the following 2 EF models:
public class Rule
{
public int Id { get; set; }
public string RuleValue { get; set; }
public bool IsActive { get; set; }
public List<Exclusion> Exclusions { get; set; }
}
public class Exclusion
{
public int Id { get; set; }
public int ApplicationId { get; set; }
public int SiteId { get; set; }
public int RuleId { get; set; }
[ForeignKey( "RuleId" )]
public Rule Rule { get; set; }
}
I want to query the database to return a List but only where there isn't a related record in the Exclusions table, based on the related RuleId, and for the specified ApplicationId and SiteId. Ultimately, taking into account any Application/Site specific exclusions, so as to not include those Rules in the results that I return.
I've been able to achieve this so far using the following query:
IQueryable<Rule> query =
from r in context.Rule
where r.IsActive && !( from e in context.Exclusion
where e.ApplicationId == applicationId &&
e.SiteId == siteId
select e.RuleId )
.Contains( r.Id )
select r;
I always use Method Syntax everywhere else and for consistency would prefer not to have just this one method that uses Query Syntax, but I've not been able to get the same thing working using Method Syntax.
Why aren't you navigating to the exclusions for this rule (r.Exclusions) instead of all Exclusiong (context.Exclusions) and then filtering on the current rule? This is very backward
If i understood your requirement right you should do:
var query = context.Rule
.Where(r=>r.IsActive)
.Where(r=>!r.Exclusions.Any(e=>e.ApplicationId == applicationId && e.SiteId == siteId);
var query = context.Rule.Where(r => r.IsActive && !context.Exclusion.Any(e => e.ApplicationId == applicationId && e.SiteId==siteId && r.Id==e.RuleId))
Directly translating:
IQueryable<Rule> query = context.Rule
.Where(r => r.IsActive && !context.Exclusion
.Where(e => e.ApplicationId == applicationId && e.SiteId == siteId)
.Select(e => e.RuleId)
.Contains(r.Id)
)
.Select(r => r);
But you can of course omit the select with the identity function (just as the compiler probably would have):
IQueryable<Rule> query = context.Rule
.Where(r => r.IsActive && !context.Exclusion
.Where(e => e.ApplicationId == applicationId && e.SiteId == siteId)
.Select(e => e.RuleId)
.Contains(r.Id)
);

Categories

Resources