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);
Related
I have the following code:
public async Task<IEnumerable<Submission>> SelectSubmissionsAsync(string submitterId, IEnumerable<Group> groups)
{
var submissions = new List<Submission>();
var apps = context.Apps
.Select(a => new
{
Id = a.Id,
Member = a.MemberHistories.OrderByDescending(ash => ash.MemberChangeDate).FirstOrDefault().Member,
Owner = a.OwnerHistories.OrderByDescending(oh => oh.OwnerChangeDate).FirstOrDefault().Owner
})
.ToDictionary(x => x.Id, x => x.Member + x.Owner);
var subs = context.Submissions.ToList();
foreach (var sub in subs)
{
if (apps.ContainsKey((Guid)sub.AppId))
{
var value = apps[(Guid)sub.AppId];
var check = value.Contains(submitterId, StringComparison.InvariantCultureIgnoreCase) || groups.Any(g => value.Contains(g.Id, StringComparison.InvariantCultureIgnoreCase));
if (check)
submissions.Add(sub);
}
}
}
public class Submission
{
public Guid Id { get; set; }
public Application App { get; set; }
public Guid? AppId { get; set; }
}
public class App
{
public Guid Id { get; set; }
public string Identifier { get; set; }
public ICollection<MemberHistory> MemberHistories { get; set;}
public ICollection<OwnerHistory> OwnerHistories { get; set;}
}
Is there a way to simplify this code (avoid for loop for example)?
Ideally you should be able to construct a single query looking something like this:
var appInfo = context.Apps
.Select(a => new
{
Id = a.Id,
Member = a.MemberHistories.OrderByDescending(ash => ash.MemberChangeDate).FirstOrDefault().Member,
Owner = a.OwnerHistories.OrderByDescending(oh => oh.OwnerChangeDate).FirstOrDefault().Owner
})
.Where(appCriteria)
;
var submissions = context.Submissions
.Where(s => appInfo.Any(app => s.AppId == app.Id))
.ToList();
That will allow your app to build a single SQL command that filters the apps down to just the ones you want before bringing them back from the database.
Building checkCriteria will be complicated, because that's going to be based on the "OR"/Union of several criteria. You'll probably want to build a collection of those criteria, and then combine them using a strategy similar to what I've defined here. If you start with a collection of values including submitterId and groupIds, each criteria would be something like s => s.Member == val || s.Owner == val.
In order to create these expressions, you'll probably need to declare a class to represent the type that you're currently using an anonymous type for, so you have a name to associate with the generic arguments on your Expression types.
I have 2 entities, Jobs and Appointments:
public class Job
{
public int JobId { get; set; }
public ICollection<Appointment> Appointments { get; set; }
}
public class Appointment
{
[Key]
public int AppointmentId { get; set; }
[Required]
public DateTime AppointmentDate { get; set; }
[Required]
[MaxLength(50)]
public string Type { get; set; }
public int Job_JobId { get; set; }
[ForeignKey("Job_JobId")]
public virtual Job Job { get; set; }
}
How do I return only jobs that have an "Initial" appointment type?
Something like the following (which isn't valid syntax):
jobs = jobs.Where(x => x.Appointments.Where(p => p.Type == "Initial"));
I believe you're looking for Any() to introduce the condition that a job must have at least one Appointment of type "Initial", viz:
var initialJobs = jobs
.Where(j => j.Appointments.Any(a => a.Type == "Initial"));
Where requires a predicate argument (Func returning a bool), and Any() returns true if at least one element meets the inner predicate (a.Type == "Initial")
If you only want to load the appointments for jobs that have the type as Initial, you could also do this:
var jobs = appointments.Where(x => x.Type == "Initial").Select(x => x.Job);
This should give you Appointments inside the jobs that only have the Initial type.
If you wanna return list of jobs as long as the list contain at least one Type == "Initial", you should use Any(), Your case seem looks like this
var jobs = jobs.Where(x => x.Appointments.Any(p => p.Type == "Initial"));
Or return job if it contains all appointments with Type == "Initial", you might use Where()
var jobs = jobs.Where(x =>
{
var appointmentCount = x.Appointments.Count();
var validAppointments = x.Appointments.Where(p => p.Type == "Initial");
return appointmentCount == validAppointments.Count();
});
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)
);
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);
I have two entities like:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public virtual ICollection<EmployeeEducation> EducationList { get; set; }
}
and
public class EmployeeEducation
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public int Type { get; set; }
[ForeignKey("EmployeeId")]
public virtual Employee Employee { get; set; }
}
My question is, how can I get a specific employee and this employee's education list ordered by Type property?
I have tried:
Employee employee = _work.EmployeeRepository.GetSet()
.SelectMany(e => e.EducationList, (e,d) => new { e, d })
.OrderBy(x => x.d.Type)
.Select(x => x.e)
.FirstOrDefault(e => e.Id == id);
But it does't seem to be sorting. What is the correct way to do this?
Thanks for everyone...
You do SelectMany(), but never use the produced EducationList part, becuase you do .Select(x => x.e). But couldn't life be simpler? After all, you only get 1 employee, why not sort its EducationList as soon as you need it, after having Included it, if necessary:
Employee employee = _work.EmployeeRepository.GetSet().Include("EducationList")
.FirstOrDefault(e => e.Id == id);
Depending if u are using POCO or not u should either use CreateSourceQuery() or Query()
In the case of POCO something like:
Employee employee = _work.EmployeeRepository.GetSet()
.SelectMany(e => e.EducationList, (e,d) => new { e, d })
.Query()
.OrderBy(x => x.d.Type)
.Select(x => x.e)
.FirstOrDefault(e => e.Id == id);