Why are my entities not being lazy loaded? - entity-framework

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;

Related

EFCore Generic Repository and UnitOfWork Design Pattern

when im trying to create new data and save it, im getting error at the
public int Complete()
{
return _context.SaveChanges();
}
and error is saying me that:
The value of 'Agency.ID' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known. .
i have a Base class like that:
public class Base
{
protected Base()
{
CreatedDate = DateTime.Now;
IsDeleted = false;
ModifiedDate = null;
}
public int ID { get; set; }
public int? CreatedUserId { get; set; }
public int? ModifiedUserId { get; set; }
public string CreatedUserType { get; set; }
public string ModifiedUserType { get; set; }
public DateTime? CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
public bool? IsActive { get; set; }
public bool? IsDeleted { get; set; }
}
i have a Agency class like that :
public class Agency : Base
{
public Agency()
{
AgencyIsComplated = false;
}
[Required, StringLength(255)]
public string AgencyName { get; set; }
[Required, StringLength(255)]
public string AgencyPhoto { get; set; }
[Required, StringLength(255)]
public string AgencyEMail { get; set; }
[Required, StringLength(13)]
public string AgencyPhone { get; set; }
[StringLength(13)]
public string AgencyBPhone { get; set; }
[StringLength(255)]
public string AgencyInfo { get; set; }
[Required, StringLength(255)]
public string AgencyTitle { get; set; }
[Required, StringLength(255)]
public string AgencyLink { get; set; }
public int AgencyExportArea { get; set; } // Join table ile yapılacak,ayrı bir tabloda tutulacak
[Required, StringLength(255)]
public string AgencyInstagram { get; set; }
public string AgencyTwitter { get; set; }
public string AgencyFacebook { get; set; }
public string AgencyLinkedin { get; set; }
public string AgencyYoutube { get; set; }
public bool AgencyIsComplated { get; set; }
[ForeignKey("CompanyID")]
public Company Company { get; set; }
[ForeignKey("LogID")]
public Log Log { get; set; }
public virtual ICollection<AgencyCompany> AgencyCompanies { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Log> Logs { get; set; }
}
public class AgencyConfiguration : IEntityTypeConfiguration<Agency>
{
public void Configure(EntityTypeBuilder<Agency> builder)
{
builder.HasKey(agency => agency.ID);
builder.HasMany(a => a.Logs)
.WithOne(a => a.Agency)
.HasForeignKey(a=>a.ID)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(us => us.Users)
.WithOne(us => us.Agency)
.HasForeignKey(au=>au.ID)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(ac => ac.AgencyCompanies)
.WithOne(ac => ac.Agency)
.OnDelete(DeleteBehavior.Restrict);
}
}
and i have got a UnitOfWork like that:
public class UnitOfWork : IUnitOfWork
{
private TradeTurkDBContext _context;
public UnitOfWork(TradeTurkDBContext context)
{
_context = context;
RepositoryAgency = new RepositoryAgency(_context);
}
public IRepository Repository { get; private set; }
public IRepositoryAgency RepositoryAgency { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
im inheriting that ID on my Base Model.
the problem is getting solved when im not defining ID in the base model but i allready set up my mapping on it.
so how can i solve that error without using AgencyID in the Agency model ?
The foreign key is in the details (or child) table. Therefore, e.g. a user, should have an AgencyId as foreign key.
builder.Entity<User>()
.HasOne(u => u.Agency)
.WithMany(a => a.Users)
.HasForeignKey(u => u.AgencyId)
.OnDelete(DeleteBehavior.Restrict);
This key automatically points to the primary key of the master (or parent) table.
User.ID is a primary key. User.AgencyId is a foreign key which (automatically) relates to the primary key Agency.ID.
E.g. see: Configure One-to-Many Relationships using Fluent API in Entity Framework Core

Referenced object is not loaded from database

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

Entity Framework - 6, Parent Key propagation to grand child object

public class Submission
{
public Submission()
{
this.VisitOccurrences = new HashSet<VisitOccurrence>();
}
public int SubmissionKey { get; set; } //PK
public string Version { get; set; }
public string ClientName { get; set; }
public string UserName { get; set; }
public DateTime SubmissionStartDate { get; set; }
public virtual ICollection<VisitOccurrence> VisitOccurrences { get; set; }
}
public class VisitOccurrence
{
public VisitOccurrence()
{
this.Observations = new HashSet<VoObservation>();
}
public int VisitOccurrenceKey { get; set; } //PK
//public int SubmissionKey { get; set; } //FK from submission . This is commented as this value inserted by EF in table. Refer to configuration below.
public string VisitConcept { get; set; }
public DateTime? VisitStartDate { get; set; }
public TimeSpan? VisitStartTime { get; set; }
public DateTime? VisitEndDate { get; set; }
public TimeSpan? VisitEndTime { get; set; }
public virtual ICollection<Observation> Observations { get; set; }
}
public class Observation
{
public int ObservationKey { get; set; } //PK
//public int VisitOccurrenceKey { get; set; } //FK from VisitOccurrence. This is commented as this value inserted by EF in table. Refer to configuration below.
//public int SubmissionKey { get; set; } // ***there is no relation on this column but I need to propagate value from parent class Submission to this grand child column when inserted Submission. What is the best way to do it?***
public string Element { get; set; }
public string ObservationConcept { get; set; }
public DateTime? ObservationDate { get; set; }
public TimeSpan? ObservationTime { get; set; }
}
public class SubmissionConfiguration : EntityTypeConfiguration<Submission>
{
public SubmissionConfiguration()
{
ToTable("Submission");
HasKey(p => p.Id).Property(p => p.Id).HasColumnName("SubmissionKey");
HasMany(p => p.VisitOccurrences).WithOptional().Map(m => m.MapKey("SubmissionKey"));
}
}
public class VisitOccurrenceConfiguration : EntityTypeConfiguration<VisitOccurrence>
{
public VisitOccurrenceConfiguration()
{
ToTable("VisitOccurrence");
Property(p => p.Id).HasColumnName("VisitOccurrenceKey");
HasMany(p => p.Observations).WithOptional().Map(m => m.MapKey("VisitOccurrenceKey"));
}
}
public class ObservationConfiguration : EntityTypeConfiguration<Observation>
{
public VoObservationConfiguration()
{
ToTable("Observation");
}
}
//Repository Method to insert Submission
public virtual void AddOrUpdate(Submission model)
{
Context.Entry(model).State = EntityState.Added;
Context.SaveChanges();
}
I have a Parent entity Submission, a Child entity VisitOccurrence and Grand child entity Observation. My configurations works When I inserted a Submission with child and grand child entities in it. All key columns populated in related tables. However, The above code inserts Submission and the identity generated in SubmissionKey is inserted in VisitOccurence and thus the VisitOccurenceKey in Observation table. But I'm looking for Configuration that could propagate SubmissionKey from VisitOccurence to Observation though there is no relation constraint added in database. please help.

EF Core could not be translated and will be evaluated locally

I have a query in EF Core 1.1.2 that is evaluated on client side and would like to know if there is a better way to translate it into sql?
The query:
from l in _ctx.Locations
join i in _ctx.Inventories on l.Id equals i.LocationId
join it in _ctx.Items on i.ItemId equals it.Id
where l.ProjectId == projectid
group i by new {l.Id, l.LHA} into il
select new InventoryLocations() {
Id= il.Key.Id,
LHA = il.Key.LHA,
FlaggedItems = il.Any(x=>x.Item != null && x.Item.Flagged)
}
If not, what other options do I have?
As I know there's still no way mapping views.
FromSQL() method can return types already known in the context only and I can not mark one model as [NotMapped] for example.
Moving back to ef6 is not an option because .net core is the target framework.
Models:
public class Location
{
public Guid Id { get; set; }
[ForeignKey("Project")]
public Guid ProjectId { get; set; }
public Project Project {get; set; }
public string Name { get; set; }
public string LHA { get; set; }
[ForeignKey("ScanUser")]
public Guid? ScanUserId { get; set; }
public User ScanUser { get; set; }
[ForeignKey("CheckUser")]
public Guid? CheckUserId { get; set; }
public User CheckUser { get; set; }
[ForeignKey("GroupLeader")]
public Guid? GroupLeaderId { get; set; }
public User GroupLeader { get; set; }
public int State { get; set; }
}
public class Inventory
{
public Guid Id { get; set; }
[ForeignKey("Project")]
public Guid ProjectId { get; set; }
public Project Project {get; set; }
public string EANCode { get; set; }
[ForeignKey("Location")]
public Guid LocationId { get; set; }
public Location Location { get; set; }
public Double ScanQty { get; set; }
[ForeignKey("ScanUser")]
public Guid? ScanUserId { get; set; }
public User ScanUser { get; set; }
public DateTime? ScanDate { get; set; }
[ForeignKey("Item")]
public Guid? ItemId { get; set; }
public Item Item { get; set; }
[ForeignKey("InventoryTask")]
public Guid? InventoryTaskId { get; set; }
public InventoryTask InventoryTask { get; set; }
[ForeignKey("CheckUser")]
public Guid? CheckUserId { get; set; }
public User CheckUser { get; set; }
public DateTime? CheckDate { get; set; }
public Double PrevQty { get; set; }
}
public class Item
{
public Guid Id { get; set; }
[ForeignKey("Project")]
public Guid ProjectId { get; set; }
public Project Project {get; set; }
public string ItemNo { get; set; }
public string EANCode { get; set; }
public string Name { get; set; }
public Double Price { get; set; }
public bool Deleted { get; set; }
public DateTime ChangeTime { get; set; }
public Double BaseQty { get; set; }
public bool Flagged { get; set; }
}
Currently (and looks like also in the incoming EF Core v.2.0) the GroupBy queries are processed locally, so the key is to avoid them where possible.
And your query seems to be eligible for that - there is no need to first multiply the data set with joins and then group it back.
I've noticed you use only reference navigation properties and FKs in your entities, basically like database table record and SQL. But EF allows you to define also a corresponding collection navigation properties which allow you to start queries from the logical root, thus eliminating the need of joins and group by.
If you define navigation property from Location to Inventory
public class Location
{
// ...
public ICollection<Inventory> Inventories { get; set; }
}
then the equivalent query could be simply:
from loc in _ctx.Locations
where loc.ProjectId == projectid
select new InventoryLocations()
{
Id = loc.Id,
LHA = loc.LHA,
FlaggedItems = loc.Inventories.Any(inv => inv.Item != null && inv.Item.Flagged)
}
which will be fully translated to SQL.
If for some reason you can't create the above collection navigation property, still you can start with locations and manually correlate them with inventories:
from loc in _ctx.Locations
where loc.ProjectId == projectid
select new InventoryLocations()
{
Id = loc.Id,
LHA = loc.LHA,
FlaggedItems = _ctx.Inventories.Any(inv => loc.Id == inv.LocationId && inv.Item != null && inv.Item.Flagged)
}
If you add the navigation property as Ivan correctly suggests:
public class Location
{
// ...
public ICollection<Inventory> Inventories { get; set; }
}
Then you can simply create a query like this:
var locations = _ctx.Locations
.Include(x => x.Inventories)
.ThenInclude(x => x.Item)
.Where(x => x.ProjectId == projectId)
.Select(loc => new InventoryLocations
{
Id = loc.Id,
LHA = loc.LHA,
FlaggedItems = loc.Inventories.Any(inv => inv.LocationId == loc.Id && inv.Item?.Flagged)
});

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