Load related entities with a single .Include() in Entity Framework? - entity-framework

Is there a better way to load all the related entities?
Below is the ScholarshipRequest class which also has Scholarship, Status, Student, Program and User.
public class ScholarshipRequest
{
public int Id { get; set; }
public int Year { get; set; }
public Status Status { get; set; }
public DateTime ApplicationDate { get; set; }
public DateTime ActionDate { get; set; }
public Scholarship Scholarship { get; set; }
public Program Program { get; set; }
public Student Student { get; set; }
public User User { get; set; }
}
I am just posting Scholarship class here, rest are similar.
public class Scholarship
{
public int Id { get; set; }
public string Name { get; set; }
}
The below code works fine but is there a better way where i can use a single .Include() to load them all or may be some other way?
ScholarshipRequestRepository repo = new ScholarshipRequestRepository(dBContext);
List<ScholarshipRequest> stdList = repo.Collection()
.Include("Status").Include("Student").Include("User").Include("Scholarship")
.Where(x => x.User.Id == userId).ToList();

Related

Check if Entity is exists in deeply related Entity

I am trying to check wether an Entity exists in a deeply related Entity. Here is an picture of my model and the code I am using for the relationships.
Image
Code
public class TimeTable
{
[Key]
public Guid TimeTableId { get; set; }
public TimeTableType TimeTableType { get; set; }
// one to many relation with TrainSeries
public List<TrainSerie> TrainSeries { get; set; } = new List<TrainSerie>();
}
public enum TimeTableType
{
Type1,
Type2
}
public class TrainSerie
{
[Key]
public Guid TrainSerieId { get; set; }
// one to many with Train
public List<Train> Trains { get; set; } = new List<Train>();
// Many to one with TimeTable
public Guid TimeTableId { get; set; }
public TimeTable TimeTable { get; set; }
}
public class Train
{
[Key]
public Guid TrainId { get; set; }
public TrainType TrainType { get; set; }
// one to many with TrainActivity
public List<TrainActivity> TrainActivities { get; set; } = new List<TrainActivity>();
// many to one with TrainSeries
public Guid TrainSerieId { get; set; }
public TrainSerie TrainSerie { get; set; }
}
public class TrainActivity
{
[Key]
public Guid TrainActivityId { get; set; }
public ActivityType Act`enter code here`ivityType { get; set; }
// many to one with TrainStation
public Guid TrainStationId { get; set; }
public TrainStation TrainStation { get; set; }
// many to one with Train
public Guid TrainId { get; set; }
public Train Train { get; set; }
}
I have a list of TrainActivities and for each TrainActivity I want to check if the TrainActivity exists in a TimeTable object with TimeTableType==Type1. If so, I want to keep the TrainActivity in the list else I want to remove it from the list.
What is the easiest way to do this? I can't do this:
trainActivity.Train.TrainSerie.TimeTable.TimeTableType == TimeTableType.Type1
Because each reference navigation property is null.
I don't know what database you use and how you keep the enum in the table property TimeTable.TimeTableType, but if you change it to string you can try something like this
public class TimeTable
{
[Key]
public Guid TimeTableId { get; set; }
public string TimeTableType { get; set; }
// one to many relation with TrainSeries
public List<TrainSerie> TrainSeries { get; set; } = new List<TrainSerie>();
}
//result will be a list of TrainActivities with all properties loaded and only with TimeTableType = Type1
var result = dBcontext.TrainActivities
.Include(x => x.Train)
.ThenInclude(x => x.TrainSerie)
.ThenInclude(x => x.TimeTable)
.Where(x => x.Train.TrainSerie.TimeTable.TimeTableType == "Type1")
.ToList();

LINQ query throw exception on FirstOrDefault method

I'm using EF core, and I have a many-to-many relationship between two entity
IotaProject <--> User
Here's entities & dto related to the question
public class IotaProject
{
[Key]
public int Id { get; set; }
[Required]
public string ProjectName { get; set; }
[Required]
public DateTime Create { get; set; }
public ICollection<ProjectOwnerJoint> Owners { get; set; } = new List<ProjectOwnerJoint>();
}
public class ProjectOwnerJoint
{
public int IotaProjectId { get; set; }
public IotaProject IotaProject { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User
{
[Key]
public int Id { get; set; }
[Required]
public string FullName { get; set; }
[Required]
public string ShortName { get; set; }
[Required]
public string Email { get; set; }
public ICollection<ProjectOwnerJoint> OwnedProjects { get; set; } = new List<ProjectOwnerJoint>();
}
public class ApplicationDbContext : DbContext
{
public DbSet<IotaProject> IotaProjects { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<ProjectOwnerJoint> ProjectOwnerJoint { get; set; }
}
public class IotaProjectDisplayDto
{
public int Id { get; set; }
public string ProjectName { get; set; }
public DateTime Create { get; set; }
public UserMinDto Owner { get; set; }
public int Count { get; set; }
public IEnumerable<UserMinDto> Reviewers { get; set; }
}
public class UserMinDto
{
public int Id { get; set; }
public string FullName { get; set; }
public string ShortName { get; set; }
}
Following LINQ is the problem, the LINQ purpose is to convert IotaProject to IotaProjectDisplayDto, and key part is that Owners property of IotaProject is ICollection and Owner property in IotaProjectDisplayDto is just one single element UserMinDto, so I only need to get the first element of IotaProject's Owners and that's FirstOrDefault() comes.
IEnumerable<IotaProjectDisplayDto> results = _db.IotaProjects.Select(x => new IotaProjectDisplayDto
{
Id = x.Id,
ProjectName = x.ProjectName,
Create = x.Create,
Owner = x.Owners.Select(y => y.User).Select(z => new UserMinDto { Id = z.Id, FullName = z.FullName, ShortName = z.ShortName }).FirstOrDefault()
});
return results;
it throws run-time exception
Expression of type 'System.Collections.Generic.List`1[ToolHub.Shared.iota.UserMinDto]' cannot be used for parameter
of type 'System.Linq.IQueryable`1[ToolHub.Shared.iota.UserMinDto]'
of method 'ToolHub.Shared.iota.UserMinDto FirstOrDefault[UserMinDto](System.Linq.IQueryable`1[ToolHub.Shared.iota.UserMinDto])' (Parameter 'arg0')
I'm guessing it's probably related to deferred execution, but after read some posts, I still can't resolve it.
Any tips would be appreciated.
Right now, the only way I can get this work is I change type of Owner property in IotaProjectDisplayDto into IEnumrable, which will no longer need FirstOrDefault() to immediate execution. And later on, I manually get the first element in the client to display.
This issue happened in Microsoft.EntityFrameworkCore.SqlServer 3.0.0-preview7.19362.6
I end up downgrade to EF core stable 2.2.6 as Ivan suggested in comment, and everything works fine.

EF6 generates all the entity classes (tt .cs) in single file (eg. model.cs) and not as separate .cs file

I am using EF6. I have 2 tables Events and Users for which I used database first approach to generate the EDMX models and entity classes. Everything works fine but the entity classes are coming under a single file in this case EventSample.cs(shown below). I am not getting separate files for each entity as Event.cs and User.cs. Please let me know if this is correct and if not how to rectify it?
public partial class Event
{
public Event()
{
this.Users = new HashSet<User>();
}
public int Id { get; set; }
public string Title { get; set; }
public System.DateTime Time { get; set; }
public string Location { get; set; }
public string Description { get; set; }
public int Creator_Id { get; set; }
public virtual User User { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public partial class User
{
public User()
{
this.Events = new HashSet<Event>();
this.Events1 = new HashSet<Event>();
}
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public virtual ICollection<Event> Events { get; set; }
public virtual ICollection<Event> Events1 { get; set; }
}

Prevent webapi from returning all data from associated tables

I have a table called MemberCompany which has a record for each company a member has. the model is below. When i query it via a webapi method passing in the memberid, i can see in debug mode that it returns the one company for that member, however when i run it in the browser i can see it returns the entire list of members also. Is it possible to just return a collection of membercompany records without the two referenced tables? I commented out the initial code to include these two tables but they appear to still be being included in the response.
public partial class MemberCompany
{
public int id { get; set; }
public int membership_id { get; set; }
public string company_name { get; set; }
public string company_address1 { get; set; }
public string company_address2 { get; set; }
public string company_town_city { get; set; }
public Nullable<int> company_county { get; set; }
public string company_postcode { get; set; }
public string company_tel { get; set; }
public string company_fax { get; set; }
public string company_email { get; set; }
public string company_contact { get; set; }
public string company_web { get; set; }
public string company_country { get; set; }
public Nullable<System.DateTime> last_updated { get; set; }
public Nullable<decimal> latitude { get; set; }
public Nullable<decimal> longitude { get; set; }
public virtual counties counties { get; set; }
public virtual members members { get; set; }
}
WebAPI
[HttpGet("admin/api/membercompany/member/{member_id}")]
public IEnumerable<MemberCompany> GetByMember(int member_id)
{
var Companies = db.MemberCompanies
// .Include(t => t.counties)
//.Include(t => t.members)
.Where(m => m.membership_id == member_id);
return Companies.AsEnumerable();
}
Turn off lazy loading for the context. My best guess is it's on and the entities are loaded when the graph is serialized...
Note: that's actually a good idea in a web app and I'd recommend you do it globally, so that you don't get bitten by performance issues due to lazy loading later, and always know precisely what you'll return.

Sum related properties in entity framework

I have a problem with sum of navigation properties using entity framework
Here is my example classes
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ObservableCollection<Call> Calls { get; set; }
[NotMapped]
public decimal TotalCallDuration { get { return Calls.Sum(c => c.Value); } }
}
public class Call
{
public int Id { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public decimal Value { get; set; }
public DateTime Date { get; set; }
}
This works well but when i have hundreds of records it is very slow
How can i make this faster but without losing functionality?
Thanks
what you want to do is:
customer.TotalCallDuration = context.Call.Sum(x => x.Value).Where(x => x.CustomerID == customer.Id);