Referenced object is not loaded from database - entity-framework-core

This the table structure I have:
#region Tables
public class WorkoutProfile
{
public WorkoutProfile()
{
WorkoutExercises = new List<WorkoutExercise>();
}
[Key]
public int ProfileId { get; set; }
public string Name { get; set; }
public int Sets { get; set; }
public int RestAfterSetInSeconds { get; set; }
public virtual User User { get; set; }
public virtual ICollection<WorkoutExercise> WorkoutExercises { get; set; }
}
public class WorkoutExercise
{
[Key]
public int WorkoutId { get; set; }
public virtual Exercise Exercise { get; set; }
public int Order { get; set; }
public int WorkoutTimeInSeconds { get; set; }
public int RestAfterInSeconds { get; set; }
}
public class Exercise
{
[Key]
public long ExerciseId { get; set; }
public string Title { get; set; }
public string Visualisation { get; set; }
public bool IsDefault { get; set; } // Is exersice should be included when user first registers
}
public class User
{
[Key]
public long UserId { get; set; }
public string Email { get; set; }
public DateTime Registered { get; set; }
}
#endregion Tables
In the repository class I run the following linq query:
return context
.WorkoutProfiles.Include(w => w.WorkoutExercises)
.Where(q => q.User.UserId == userId && q.ProfileId == profileId)
.FirstOrDefault();
and I receive the good and old "Object reference not set to an instance of an object". When examining the result, see that Exercises property in WorkoutExercises is null.
This is how the database is created using code first approach:
So, the question is: why Exercises not included in WorkoutExercises object? Do I need to include it somehow? I am using .NET Core 2

The simple answer would be no lazy loading in EFCore. Not Released yet but if you want to dabble with alpha code, its in the repository. Based on your classes there are no collections for exercises in WorkoutExcercise.
Then you need to ThenInclude(w => w.Exercises) following your Include clause since EFCore doesn't do lazy loading.

I found a solution following this post
Altered my code as following:
var top = context
.Set<WorkoutProfile>()
.Where(q => q.ProfileId == profileId && q.User.UserId == userId)
.Include(q => q.WorkoutExercises)
.SingleOrDefault();
context
.Entry(top)
.Collection(e => e.WorkoutExercises)
.Query()
.OfType<WorkoutExercise>()
.Include(e => e.Exercise)
.Load();
And it worked

Related

Entity Framework Core Automapper latest viewed items for a specific user

Using Entity Framework Core, I would like to get a list of the 10 most recently viewed jobs by a user.
I am working on a CRM which contains User, Job and UserJobView classes.
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class Job
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
public class UserJobView
{
public Guid Id { get; set; }
public Guid JobId { get; set; }
public Guid UserId { get; set; }
public DateTime LastViewedAt { get; set; }
public Job Job { get; set; }
}
I also have a JobDto which I project to using AutoMapper
public class JobDto : IMapFrom<Job>
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime? LastViewedAt { get; set; }
}
Each time a User views a Job I either update or create a UserJobView object setting the LastViewedAt property to be DateTime.Now
I can get the latest viewed items with the following fluent query
return await _context.UserJobViews
.Where(x => x.UserId == thisUserId)
.OrderByDescending(x => x.LastViewed)
.Take(10)
.Select(x => x.Job)
.ProjectTo<JobDto>(_mapper.ConfigurationProvider)
.ToListAsync();
However this obviously doesn't populate the LastViewedAt property for the JobDto. How might I go about doing this?
With a small addition to your configuration, you can make it happen:
CreateMap<UserJobView, JobDto>().IncludeMembers(s => s.Job);

Load related entities with a single .Include() in 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();

Why are my entities not being lazy loaded?

I'm using EF 6 and defining my database with Code First.
The following line of code returns a Transaction entity, however the EndorsementInfo navigation property is null. I've checked the database and there is definitely data for the test data. "var trans" does appear to have a valid IQueryable, but navigation property t.EndorsementInfo is null when it shouldn't be.
var trans = unitOfWork.GetRepository<Transaction>().GetAll().Where(t => t.PolicyId == command.PolicyId);
results.Transactions = new List<TransactionListItem>();
foreach (var t in trans)
{
results.Transactions.Add(new TransactionListItem
{
Id = t.Id,
EffDate = t.EffectiveDate,
EffectiveDate = t.EffectiveDate.ToShortDateString(),
TransactionType = t.TransactionType.ToStringValue(),
EndorsementType = t.TransactionType == TransactionType.Endorsement ?
t.EndorsementInfo.EndorsementType.Description : ""
});
}
Transaction Entity:
public class Transaction : EntityBase
{
[Required]
public TransactionType TransactionType { get; set; }
public long PolicyId { get; set; }
public virtual Policy Policy { get; set; }
[Required]
public DateTime EffectiveDate { get; set; }
public DateTime? ExpirationDate { get; set; }
public string Description { get; set; }
public virtual Quote QuoteInfo { get; set; }
public virtual Cancellation CancellationInfo { get; set; }
public virtual NewBusiness NewBusinessInfo { get; set; }
public virtual Endorsement EndorsementInfo { get; set; }
}
Endorsement Entity
public class Endorsement : EntityBase
{
public Transaction Transaction { get; set; }
public long EndorsementTypeId { get; set; }
public virtual EndorsementType EndorsementType { get; set; }
public int EndorsementNum { get; set; }
[MaxLength(500)]
public string EndorsementDesc { get; set; }
public Decimal? Premium { get; set; }
}
Code First Fluent Configurations
public class TransactionConfiguration : EntityTypeConfiguration<Transaction>
{
public TransactionConfiguration()
{
HasOptional(t => t.QuoteInfo).WithRequired(q => q.Transaction);
HasOptional(t => t.NewBusinessInfo).WithRequired(q => q.Transaction);
HasOptional(t => t.EndorsementInfo).WithRequired(q => q.Transaction);
HasOptional(t => t.CancellationInfo).WithRequired(q => q.Transaction);
}
}
Repositories implementation of GetAll
public IQueryable<T> GetAll(string include)
{
return _set.Include(include);
}
I've checked and rechecked that everything is set up correctly. I don't know what I could be missing.
Thanks.
You are using an opened connection to execute two data readers, you need to enable the multiple result set in the connection string.
MultipleActiveResultSets=True;

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);

Entity Framework Code First Many to Many Setup For Existing Tables

I have the following tables Essence, EssenseSet, and Essense2EssenceSet
Essense2EssenceSet is the linking table that creates the M:M relationship.
I've been unable to get the M:M relationship working though in EF code first though.
Here's my code:
[Table("Essence", Schema = "Com")]
public class Essence
{
public int EssenceID { get; set; }
public string Name { get; set; }
public int EssenceTypeID { get; set; }
public string DescLong { get; set; }
public string DescShort { get; set; }
public virtual ICollection<EssenceSet> EssenceSets { get; set; }
public virtual EssenceType EssenceType { get; set; }
}
[Table("EssenceSet", Schema = "Com")]
public class EssenceSet
{
public int EssenceSetID { get; set; }
public int EssenceMakerID { get; set; }
public string Name { get; set; }
public string DescLong { get; set; }
public string DescShort { get; set; }
public virtual ICollection<Essence> Essences { get; set; }
}
[Table("Essence2EssenceSet", Schema = "Com")]
public class Essence2EssenceSet
{
//(PK / FK)
[Key] [Column(Order = 0)] [ForeignKey("Essence")] public int EssenceID { get; set; }
[Key] [Column(Order = 1)] [ForeignKey("EssenceSet")] public int EssenceSetID { get; set; }
//Navigation
public virtual Essence Essence { get; set; }
public virtual EssenceSet EssenceSet { get; set; }
}
public class EssenceContext : DbContext
{
public DbSet<Essence> Essences { get; set; }
public DbSet<EssenceSet> EssenceSets { get; set; }
public DbSet<Essence2EssenceSet> Essence2EssenceSets { get; set; }
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<Essence>()
.HasMany(e => e.EssenceSets)
.WithMany(set => set.Essences)
.Map(mc =>
{
mc.ToTable("Essence2EssenceSet");
mc.MapLeftKey("EssenceID");
mc.MapRightKey("EssenceSetID");
});
}
}
This is the code I'm trying to run:
Essence e = new Essence();
e.EssenceTypeID = (int)(double)dr[1];
e.Name = dr[2].ToString();
e.DescLong = dr[3].ToString();
//Get Essence Set
int setID = (int)(double)dr[0];
var set = ctx.EssenceSets.Find(setID);
e.EssenceSets = new HashSet<EssenceSet>();
e.EssenceSets.Add(set);
ctx.Essences.Add(e);
ctx.SaveChanges();
And here's the error:
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception.
I'm not able to find the problem. I'd greatly appreciate help setting this up right.
Thanks!
Remove your Essence2EssenceSet model class. If junction table contains only keys of related entities participating in many-to-many relations it is not needed to map it as entity. Also make sure that your fluent mapping of many-to-many relations specifies schema for table:
mb.Entity<Essence>()
.HasMany(e => e.EssenceSets)
.WithMany(set => set.Essences)
.Map(mc =>
{
mc.ToTable("Essence2EssenceSet", "Com");
mc.MapLeftKey("EssenceID");
mc.MapRightKey("EssenceSetID");
});