Entity Framework include with where clause - c#

I am currently working on a cinema booking system for a school project and have run into a problem.
I have a Movie model which contains a list of show models(date and time for the viewing of the movie). I need to get all the movie objects that are shown on a specific date with a list containing only the Show objects which date is equal to the specific date. I have tried various ways to do it in entity but cant seem to get it to work.
Here is the Movie class:
[DataContract]
public class Movie
{
[Key, Required, DataMember]
public Guid Id { get; set; }
[Required, DataMember]
public string Name { get; set; }
[Required, DataMember]
public string Info { get; set; }
[Required, DataMember]
public DateTime Premiere { get; set; }
[Required, DataMember]
public MovieType Type { get; set; }
[DataMember]
public ICollection<Show> Shows { get; set; }
[DataMember]
public string IMDBID { get; set; }
}
public enum MovieType
{
Movie2D = 0,
Movie3D = 1,
KidsMovie = 2
}
Here is the Show class:
[DataContract]
public class Show
{
[Key, Required, DataMember]
public Guid Id { get; set; }
[Required, DataMember]
public Guid MovieId { get; set; }
[Required, DataMember]
public Guid ScreenId { get; set; }
[Required, DataMember]
public DateTime DateTime { get; set; }
[Required, DataMember]
public ShowType Type { get; set; }
[DataMember]
public Screen Screen { get; set; }
[DataMember]
public Movie Movie { get; set; }
}
public enum ShowType
{
Standard = 0,
Premiere = 1,
}
Here is the GetMovies(DateTime date) method:
public List<Movie> GetMovies(DateTime date)
{
using (EntityContext db = new EntityContext())
{
List<Movie> movieList = db.Movies
.Include("Show")
.Where(x => x.Shows.Where(x => x.DateTime.Date == date.Date)).ToList();
return movieList;
}
}
I know that this function isn't working but hope it would show what I am trying to do.

I think DateTime.Date is not supported in Linq to Entities. You could use DbFunctions.TruncateTime static method:
var justDate= date.Date;
var movieList=db.Movies.Include(x=>x.Shows)
.Where(x => x.Shows.Any(x => DbFunctions.TruncateTime(x.DateTime) == justDate))
.ToList();
Update:
After read #Jonathan's comment I did a little research and it's true using DbFunctions.TruncateTime could affect the performance. You can find a detailed explanation in this post.
Following the same idea of #JonathanAllen and #MattJohnson, you can avoid to use that function if you do a range query instead, truncating first the Time from date parameter:
var startDate= date.Date;
var endDate= startDate.AddDays(1);
var movieList=db.Movies.Include(x=>x.Shows)
.Where(x => x.Shows.Any(x =>x.DateTime >= startDate && x.DateTime < endDate)
.ToList();

You should be able to use Any
public List<Movie> GetMovies(DateTime date)
{
using (EntityContext db = new EntityContext())
{
List<Movie> movieList = db.Movies.Include("Show")
.Where(x => x.Shows.Any(x => x.DateTime.Date == date.Date));
return movieList;
}
}

My request good working with All() method.
model.ReferenceList = db.JournalCardReference.OrderBy(a => a.orderF)
.Include(x => x.JournalCardField)
.Where(x => x.JournalCardField
.All(f => f.deleted == null || f.deleted != true)).ToList();

Related

Entity Framework Select top row from each type based on subobject value

I am using EF6 Code First approach. I have a the following related tables Events, Markets, MarketTypes with these models
public class Event
{
public Guid ID { get; set; } = Guid.NewGuid();
public List<Market> Markets { get; set; } = new List<Market>();
}
public class Market
{
public Guid ID { get; set; } = Guid.NewGuid();
public Guid EventID { get; set; }
public Event Event { get; set; }
public Guid TypeID { get; set; }
public MarketType Type { get; set; }
public DateTime InitiateDateTime { get; set; }
public DateTime LastUpdateDateTime { get; set; }
public double Value { get; set; }
}
public class MarketType
{
public Guid ID { get; set; } = Guid.NewGuid();
public string Name { get; set; }
public int Order { get; set; }
}
Each event have many markets and each market has one type. I am using the following statement to get list of events.
List<Event> events = new List<Event>();
var startDate = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day);
var endDate = startDate.AddHours(24);
events = _context.Events
.Include(e => e.Markets)
.Include(e => e.Markets.Select(i => i.Type))
.Where(e => e.DateTime >= startDate)
.Where(e => e.DateTime < endDate)
.OrderBy(e => e.DateTime)
.ToList();
Is it possible to update the above query in order to retrieve one market row of each type which is the last updated one (having largest 'LastUpdateDateTime' value). I am currently doing this through an ugly manual method.
if your want last updated values, I use in this case OrderByDescending, that will be sort a list with last .
like this:
_context.Events
.Inlcude(e=>e.Markets)
.Include(e=>e.Markets.Select(I=>I.Type))
.Where(e=>e.DateTime>= startDate && e.DateTime<endDate)
.OrderBy(e.DateTime)
.OrderByDescending(e.LastUpdateDateTime )
.ToList();
you can't use ThenbBy linq cmd because OrderBy is for ascending and it is in conflict with OrderByDescending.
with this you have a list.
After you need the cmd First() or FirstOrDefault() to get only the largest one.
I am not sure but if you use cmd FirstOrDefault() instead of where cmd it could be work.
is it good for you?

Unable to populate an ICollection with related data in Entity Framework

I have tables with created using below models in Entity Framework
public class User
{
public int Id{ get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public ICollection<AssigneeMonth> AssigneeMonths { get; set; }
}
public class AssigneeMonth
{
public int Id { get; set; }
public int AssigneeId { get; set; }
public Month Month { get; set; }
public User Assignee { get; set; }
}
public class ProjectAssignee
{
public int Id { get; set; }
public int ProjectId { get; set; }
public int AssigneeId { get; set; }
public bool IsActive { get; set; }
public AutomationProject Project { get; set; }
[ForeignKey("AssigneeId")]
public User User { get; set; }
}
I am trying to get data into the collection AssigneeMonths from AssigneeMonth using this code:
var assn = dataContext.ProjectAssignees
.Where(r => r.Project.Name == project.Name && r.IsActive)
.Include(u => u.User)
.ToList();
But AssigneeMonths collection in the above assn is always null even if I have data in AssigneeMonth for the user
May I know what's wrong with the above code?
Since you're using eager loading, you're only loading the information for user, not its navigational properties.
You can use the code in this answer, which applied to your case will look like this:
var assn = dataContext.ProjectAssignees
.Where(r => r.Project.Name == project.Name && r.IsActive)
.Include(u => u.User.SelectMany(u => u.AssigneeMonths))
.ToList();
Since AssigneeMonths is a collection, you need to use SelectMany instead of Select.
Other option would be to do it like this (as posted in other answers in that link):
var assn = dataContext.ProjectAssignees
.Where(r => r.Project.Name == project.Name && r.IsActive)
.Include(u => u.User)
.Include("User.AssigneeMonths")
.ToList();
But I personally don't like the second method because its easy to make mistakes with the string and it will hide the errors until runtime.

Entity Framework - Loading Subclass Entities with TPT Setup

Our system is receiving input from two external sources (phone call/web submission).
// Table-Per-Type Hierarchy
public class Submission
{
public int SubmissionId { get; set; } // Primary Key
public int? PersonId { get; set; }
public int? CompanyId { get; set; }
public long? EmployeeId { get; set; }
public bool? Completed { get; set; }
public string AbsenceReason { get; set; }
public string AbsenceType { get; set; }
public DateTime? AbsenceDate { get; set; }
}
public class CallSubmission : Submission
{
public string CallerId { get; set; }
public string PhoneNumber { get; set; }
public DateTime? HangUp { get; set; }
public DateTime? PickUp { get; set; }
}
public class WebSubmission : Submission
{
public string EmailAddress { get; set; }
public string PhoneNumber { get; set; }
public DateTime SubmissionDate { get; set; }
}
My goal is to retrieve all submissions within the past seven days using PickUp/SubmissionDate depending on the type of submission we're dealing with. Is it possible to achieve this with a single LINQ statement? Ideally, I'd like to avoid having to load two different data sets in-memory.
Statements I'm hoping to integrate
Users.Where(user => user.UserName == name)
.SelectMany(user => user.Submissions)
.OfType<CallSubmission)()
.Where(call => call.PickUp >= startDate)
Users.Where(user => user.UserName == name)
.SelectMany(user => user.Submissions)
.OfType<WebSubmission>()
.Where(web => web.SubmissionDate >= startDate)
Actually (surprisingly for me) what are you asking is possible (at least in the latest EF6.1.3) since the C# is and as operators are supported (they are basically used by OfType method).
var query = db.Users
.Where(user => user.UserName == name)
.SelectMany(user => user.Submissions)
.Where(subm => (subm as CallSubmission).PickUp >= startDate
|| (subm as WebSubmission).SubmissionDate >= startDate);
The important part is to use as operator and not cast which generates unsupported exception. There is no need to check for null because the generated SQL query handles NULLs naturally.

Error iterating the query results

I have a context called companyContext. There are Three tables Reports,Logs and Employees.I am given a case id and I need to get a list of all the employees who belong to a certain case (and a log if there is one, but i dont need to worry about that yet). So I made a query get all the employees where EmployeeID is equal to Employee.ID, where the Reports CaseID is eaual to case.id. However, its not reutning a list, its returning a Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable}]
Am I making the query correctly ? Thanks guys.
var employees = await context.Reports.Include(s => s.Employee)
.ThenInclude(e => e.ID)
.AsNoTracking()
.Where(r => r.CaseID == Case.Id);
Models
public class Log
{
public int ID { get; set; }
public string Input { get; set; }
public string Tag { get; set; }
public DateTime LogDate { get; set; }
public ICollection<Report> Reports { get; set; }
}
public class Employee
{
public int ID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public ICollection<Report> Reports { get; set; }
}
public class Report
{
public int ID { get; set; }
public string CaseID { get; set; }
public int EmployeeD { get; set; }
public int? LogID { get; set; }
public Employee Employee { get; set; }
public Log Log { get; set; }
}
SingleOrDefaultAsync
throws an exception if there is more than one element in the sequence.
So you should not be using SingleOrDefaultAsync if you expect multiple records.
If I'm interpreting your question properly and you want employees themselves, you could start with them and then narrow via the Employee class's .Reports navigation property.
var employees = await context.Employees.AsNoTracking()
.Where(e => e.Reports.Any(r => r.CaseID == case.Id))
.ToListAsync();
So entity is actually like using a real database. I had to do a where and select clause, but also a toList to convert it into something readable.
var employees = await context.Reports.Where(r => r.CaseID == Case.Id);
.Select(r => r.Employee)
.ToList();

Transforming into another object using LINQ Grouping

I have a list of exams which has happened on a particular time, and the mark obtained by a student for that Exam contained in an object as below:
class Exam
{
public DateTime? DateTime { get; set; }
public double? Mark { get; set; }
public string Student { get; set; }
public int Age { get; set; }
}
I need to transform this into another format for display purposes using the following structure:
class ExamViewModel
{
public DateTime? DateTime { get; set; }
public double? Mark { get; set; }
List<StudentVieWModel> Students { get; set; }
}
class StudentVieWModel
{
public string Student { get; set; }
public int Age { get; set; }
}
class ResultViewModel
{
List<ExamViewModel> Exams { get; set; }
}
Basically what I want ot display is an exam which has taken place at a particuar date, and the total marks achieved in that by all student (S1 = 10, S2 = 20, Total = 30 at 19/06/2014). The students should be transformed into the Student ViewModel so that I can see who all students have attended the exam. How can I do this using LINQ?
Thanks,
-Mike
Note: Using .NET4
Tried:
exams.OrderBy(x=>x.DateTime)
.GroupBy(x => x.DateTime, x=> x, (d, students) => new{Date= x, Students = students.ToList()} );
But cant get the total of marks..:(
It's cleaner IMHO to use a GroupBy with a subsequent Select instead of using the overload of GroupBy that includes a projection:
var query =
exams.GroupBy(x => x.DateTime)
.Select(g => new {
Date = g.Key,
TotalMarks = g.Sum(s => s.Mark)
}
);

Categories