EF6 LinQ - Select descendants where matching expression - entity-framework

I want to filter the descendants of School by one expression. Is this possible? I want only the pupils with the Age of "12"
Pseudocode
context.Schools.Where(s => s.Name = "Springfield Elementary").Where(s =>
s.Pupils.Age == 12).Select(s);
Basically i want a Collection of Schools which has an Collection of pupils where match my expression
Thanks!

context.Schools.Where(s => s.Name == "Springfield Elementary" && s.Pupils.Age == 12);
It shouldn't be nessesary to .Select(s) school since that's what you are querying.
This returns the Schools that have pupils age 12.
But if you want to select the pupils instead you need to:
context.Schools
.Where(s => s.Name == "Springfield Elementary" && s.Pupils.Age == 12)
.Select(s=>s.Pupils);
Or as suggested by comments querying the pupils instead
context.Pupils.Where(s => s.Age == 12 && s.School.Name == "Springfield Elementary");
This assumes that Schools/Pupil looks something like this (code-first POCOs):
public class School
{
public int SchoolId { get; set; }
public string Name { get; set; }
public virtual ICollection<Pupil> Pupils { get; set; }
}
public class Pupil
{
public int PupilId { get; set; }
public int Age { get; set; }
public int SchoolId { get; set; }
public virtual School School { get; set; }
}

Related

Get result collection of two child tables joined by one parent table in linq

I have 3 entities: Surveys, Batch, and Removedwhere Surveys is the parent table and the other two are related to Surveys with foreign keys.
public class Surveys
{
public int TireID { get; set; }
public dateTime DateCreated{ get; set; }
}
public class Batch
{
public int TireID { get; set; }
public int TirePosition{ get; set; }
public ICollection<Surveys> Survey{ get; set; }
}
public class Removed
{
public int TireID { get; set; }
public int TirePosition{ get; set; }
public dateTime DateRemoved{ get; set; }
public ICollection<Surveys> Survey{ get; set; }
}
I have a query to get the Batch of tires that formed part of the Survey, and the removed ones from Removed:
var surveys = ctx.Surveys.Where(a => a.DateSubmitted >= startDate && a.DateSubmitted < endDate).Select(a => new T_Batch
{
//don't know how to get desired result
}).ToList();
I have a custom type that the query result (T_Batch) should be of:
public class T_Batch
{
public int TireID { get; set; }
public int TirePosition { get;
public T_Removed Removed{ get; set; }
}
public class T_Removed
{
public int TireID { get; set; }
public int TirePosition { get; set; }
}
The query result brings back a list of Surveys which is fine, but I would like a list of tires per Survey list item, and a removed tire (if there was one removed) per tire position. I don't know how to achieve this.
Example of desired result:
0 Batch_Tire1
1 Batch_Tire2
0 Removed_Tire
2 Batch_Tire3
3 Batch_Tire4
0 Removed_Tire
etc...
UPDATE
I could do something like this, but I need to get the result set as my custom type.
var surveys = ctx.TM_Survey.Where(a => a.DateSubmitted >= startDate && a.DateSubmitted < endDate).Select(a => new
{
BatchItem = a.Batch,
RemovedItem = a.Removed
}).ToList();
UPDATE 2
Or I could do this, but the result only returns a limited number of rows equal to the number of keys in TM_Survey
var surveys = ctx.TM_Survey.Where(a => a.DateSubmitted >= startDate && a.DateSubmitted < endDate).Select(a => new T_Batch
{
TireID = a.T_Batch.Select(b => b.ID).First(),
TirePosition = a.T_Batch.Select(b => b.TirePosition).First()
Removed = new T_Removed
{
//...etc
}
}).ToList();

NOT IN filter in a query with a join of two collections using MongDB C# driver

I have two collections that can be modelled with these classes (simplified version):
public class Profile
{
[BsonId]
[BsonRepresentation(BsonType.String)]
public Guid? Id { get; set; }
public string Name { get; set; }
[BsonRepresentation(BsonType.String)]
public Guid UserId { get; set; }
}
public class User
{
[BsonId]
[BsonRepresentation(BsonType.String)]
public Guid? Id { get; set; }
public string UserName { get; set; }
public bool IsConfirmed { get; set; }
}
I need a query to get all the UserProfiles whose User has the IsConfirmed flag equals true, and then I need to filter out the ones whose Id is included in a list of excluded Ids:
IList<Guid> profileIdsToExclude
This is the query I've built so far:
var professionalProfilesQuery =
(from profileCollection in _mongoContext.Database.GetCollection<Profile>("profiles").AsQueryable()
join userCollection in _mongoContext.Database.GetCollection<User>("users").AsQueryable()
on profileCollection.UserId equals userCollection.Id.Value
into users
orderby profileCollection.Name
select new ProfessionalProfile
{
Id = profileCollection.Id,
Name = profileCollection.Name,
UserId = profileCollection.UserId,
IsConfirmed = users.First().IsConfirmed,
})
.Where(p => p.IsConfirmed && !profileIdsToExclude.Contains(p.Id.Value));
Where ProfessionalProfile is a class to return the query result:
public class ProfessionalProfile
{
public Guid? Id { get; set; }
public string Name { get; set; }
public Guid UserId { get; set; }
public bool IsConfirmed { get; set; }
}
I get UserProfiles, only the ones with IsConfirmed equals true. But the ones whose Id is in the list of excluded Ids are not filtered out and are returned by the query.
Any idea if what I want to do is possible and how?
Thanks in advance.
Your problem here is caused by a little type confusion.
The query that the driver creates contains a $match stage at the end that looks kind of like this:
{
$match: {
IsConfirmed: true,
Id: {
$nin: [ BinData(3, "DBA38D51FC28094BA2D6439E95643A49") ]
}
}
}
So it is actually trying to exclude results that have a field with a particular Guid value. You are, however, storing strings for your Guids so the filter does not exclude anything. In order to fix that here is what you could do:
Change
.Where(p => p.IsConfirmed && !profileIdsToExclude.Contains(p.Id.Value));
into
.Where(p => p.IsConfirmed && !profileIdsToExclude.Contains(p.Id));
and
IList<Guid> profileIdsToExclude
into
IList<Guid?> profileIdsToExclude

How to get rows of Data from Multiple Tables using LinQ To Entities

I am using dbcontext Code first to get a query base on this condition for the Classes (tables) below:
Creator != null && ArticleAttached != null && !IsCancelled
var ArticleStudentLiked = dbcontext.LearningActivites
.Where(la => la.Creator != null && la.ArticleAttached != null && !la.IsCancelled)
.Sum(la => la.ArticleAttached.StudentsLiked.Count);
var NewsArticleComment = dbcontext.LearningActivites
.Where(la => la.Creator != null && la.ArticleAttached != null && !la.IsCancelled)
.Sum(la => la.ArticleAttached.Comments.Count);
The following Methods only return count for:
ArticleStudentLiked
ArticleComment
I need to get rows of record from the Queries into a single collection which I can pass to View to display line by line
like this :
Article Title, No. of Likes, No. Of Comments
How to use LinQ to Get these : Article Title,No. Of Like , No. of Comment
Classes:
public class LearningActivity
{
public virtual ArticleCreator Creator { get; set; }
public virtual ArticleCreator EditedBy { get; set; }
public virtual Teacher CreatedByTeacher { get; set; }
public virtual Article ArticleAttached { get; set; }
public virtual Article ArticleAttachedByOther { get; set; }
public bool IsCancelled { get; set; }
}
public class Article
{
public string ArticleTitle {get;set;}
public virtual IList<Teacher> TeachersLiked { get; set; }
public virtual IList<Student> StudentsLiked { get; set; }
public virtual IList<ArticleComment> Comments { get; set; }
}
public class Student
{
public virtual IList<ArticleCommentStudent> Comments { get; set; }
}
Thanks
Can you try this
// LikeCount is total of Teacher and Student Likes
// and where clause can be added before Select
var result = dbcontext.Classes
.Select(x=> new { ArticleTitle = x.ArticleTitle,
LikeCount = x.TeachersLiked.Count() + x.StudentsLiked.Count(),
CommentCount= x.Comments.Count }).First();

EF6 Self Referencing Table with multiple parent properties, single child collection

I have a table that references itself, but I am struggling with getting my desired mapping. I want to be able to define Children to be a collection of people that have a given person as Mother, Father, and/or Guardian. A Guardian may be the father or mother.
I am wanting to have a tree view of people that is browsable where people are listed; the user can expand a person's node to show all that person's children, regardless off the child-defining relationship (Mother, Father, or Guardian).
public partial class Person
{
[Key]
public int ID { get; set; }
[StringLength(100)]
public string Name { get; set; }
public int? GuardianID { get; set; }
[Column("MotherID")]
public int? MotherID { get; set; }
[Column("FatherID")]
public int? FatherID { get; set; }
[ForeignKey("MotherID")]
public virtual tblPerson Mother { get; set; }
[ForeignKey("FatherID")]
public virtual tblPerson Father { get; set; }
[ForeignKey("GuardianID")]
public virtual tblPerson Guardian { get; set; }
[InverseProperty("Guardian")]
[InverseProperty("Father")]
[InverseProperty("Mother")]
public virtual IEnumerable<tblPerson> children { get; set; }
}
Any help would be appreciated right now my view has to look like this:
#using Person_MVC.Models
#model IEnumerable<Person>
#{
IEnumerable<Person> children;
}
<ul>
#foreach (Person person in Model.OrderBy(p => p.PersonNumber))
{
<li id="Pnl_#Person.ID" data-jstree='{"type":"Person"}' data-Personkey="#Person.ID.ToString()">
#Person.Name
#{
PersonModel db = new PersonModel();
children = (from p in db.Persons where p.GuardianID == Person.ID || p.Father == Person.ID || p.MotherID == Person.ID select p).ToList();
}
#if (children != null && children.Count() > 0)
{
#Html.Partial("PersonTree", children)
}
</li>
}
</ul>
I guess the better solution is to make three navigation lists in your model and may have one method to join the objects to return all sons to you.
e.g.
public int? FatherId { get; set; }
public int? GrandFatherId { get; set; }
public int? MotherId { get; set; }
public virtual ICollection<Person> FatherForThose { get; set; }
public virtual Person Father { get; set; }
public virtual ICollection<Person> GrandFatherForThose { get; set; }
public virtual Person GrandFather { get; set; }
public virtual ICollection<Person> MotherForThose { get; set; }
public virtual Person Mother { get; set; }
public ICollection<Person> GetChildren()
{
var list = FatherForThose.Concat(MotherForThose).ToList();
foreach (var person in GrandFatherForThose)
{
if (list.All(i => i.Id != person.Id))
{
list.Add(person);
}
}
return list;
}
but you should always take care to include them in your querying
e.g.
var grand = context.Persons.Include(x => x.FatherForThose)
.Include(x => x.GrandFatherForThose)
.Include(x => x.MotherForThose)
.FirstOrDefault(x => x.Id == 2);
var list = grand.GetChildren();
All the table data should be in hand (If not we might have multiple calls to database).
Find list of all the Persons who doesn't have parents(i.e; no guardianid, motherid, parentid for a person) and start the partial with them.
Try can this too...
public partial class Person
{
[Key]
public int ID { get; set; }
[StringLength(100)]
public string Name { get; set; }
public int? GuardianID { get; set; }
[Column("MotherID")]
public int? MotherID { get; set; }
[Column("FatherID")]
public int? FatherID { get; set; }
public IEnumerable<Person> Children { get
{
return context.Person.Where(p => p.GuardianID == this.ID || p.Father == this.ID || p.MotherID == this.ID).ToList();
}
}
}
#using Person_MVC.Models
#model IEnumerable<Person>
<ul>
#foreach (Person person in Model.OrderBy(p => p.PersonNumber))
{
<li id="Pnl_#Person.ID" data-jstree='{"type":"Person"}' data-Personkey="#Person.ID.ToString()">
#Person.Name
#if (Person.Children != null && Person.Children.Count() > 0)
{
#Html.Partial("PersonTree", Person.Children)
}
</li>
}
</ul>

Compare property of model in the list with the constant value

Its a simple question but I am starting with EF and dont know:
I have two classes (db objects):
Company (simplified)
public class Company
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<UserGroup> UserGroups { get; set; }
}
and userGroup (there are many users in the group):
public class UserGroup
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<ApplicationUser> Users { get; set; }
public virtual ICollection<Company> Companies { get; set; }
}
In controller I need to select the companies which have a specific UserGroupID. I dont know how to write the select condition. I mean something like:
var currentUser = db.Users.Find(User.Identity.GetUserId());
var companies = db.Companies
.Include(c => c.Address)
.Include(c => c.User)
.Where(c => c.UserGroups == currentUser.UserGroup)
;
It would be helpful to see your ApplicationUser class, but I suppose it has a navigation property to UserGroup? If it does, you could do it like this:
db.Users.Where(u => u.Id == User.Identity.GetUserId())
.SelectMany(u => u.UserGroups)
.SelectMany(g => g.Companies)
.Distinct();
I like to write the where clause over entity I want to return. In your case:
db.Companies.Where(c => c.UserGroups.Any(g => g.ID == currentUser.UserGroup.ID));
This way you don't have to add the Distinct().