Reputation: 17
At first, here what I have:
4 Classes have some relations between them as:
Project has many Bridges.
Bridge has many Foundations.
Foundation has many PierCaps and many PierColumns.
Project.cs:
public class Project
{
public Project()
{
Bridges = new HashSet<Bridge>();
StartDate = DateTime.Now;
EndDate = DateTime.Now;
}
// Fields
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
// Calculated Fields
public int BridgeCount => Bridges.Count;
public int PierFoundationCount = 0;
public int PierCapCount = 0;
public int PierColumnCount = 0;
// Relation To Children
public virtual ICollection<Bridge> Bridges { get; private set; }
}
Bridge.cs:
public class Bridge : BasicBaseEntityWithName
{
public Bridge()
{
PierFoundations = new HashSet<PierFoundation>();
}
// Fields
public int ProjectID { set; get; }
public Project Project { set; get; }
// Calculated Fields
public int PierFoundationCount => PierFoundations.Count;
public int PierCapCount => PierFoundations.Count;
public int PierColumnCount => PierFoundations.Count;
// Relation To Children
public ICollection<PierFoundation> PierFoundations { get; private set; }
}
PierFoundation.cs:
public class PierFoundation : BasicBaseEntityWithName
{
public PierFoundation()
{
PierCaps = new HashSet<PierCap>();
PierColumns = new HashSet<PierColumn>();
}
// Fields
public float Length { set; get; }
// Calculated Fields
public int PierColumnCount => PierColumns.Count;
public int PierCapCount => PierCaps.Count;
public float FoundationQty => (Length * Width * Height);
// Relations To Parents
public int BridgeID { set; get; }
public Bridge Bridge { set; get; }
// Relations To Children
public ICollection<PierCap> PierCaps { get; set; }
public ICollection<PierColumn> PierColumns { get; set; }
}
PierColumn.cs:
public class PierColumn : BaseEntityNoName
{
// Fields
public float Diameter { set; get; }
// Relations To Parents
public int PierFoundationID { set; get; }
public PierFoundation PierFoundation { set; get; }
}
PierCap.cs:
public class PierCap : BaseEntityNoName
{
// Fields
public float CapWidth { set; get; }
// Relations To Parents
public int PierFoundationID { set; get; }
public PierFoundation PierFoundation { set; get; }
}
BaseEntityNoName.cs:
public class BaseEntityNoName
{
public BaseEntityNoName()
{
AddedBy = Core.General.Global.CurrentUseId;
AddedDate = DateTime.Now;
}
public int Id { get; set; }
public DateTime AddedDate { get; set; }
public int AddedBy { get; set; }
// Becuase they will not appear at new, they will be nullable
public DateTime? ModifiedDate { get; set; }
public int? ModifiedBy { get; set; }
}
BasicBaseEntityWithName.cs:
public class BasicBaseEntityWithName : BaseEntityNoName
{
public string Name { get; set; }
}
Adding to that, I have this method in my Repository:
public IEnumerable<TEntity> Include(params Expression<Func<TEntity, object>>[] includeExpressions)
{
DbSet<TEntity> dbSet = Context.Set<TEntity>();
IEnumerable<TEntity> query = null;
foreach (var includeExpression in includeExpressions)
{
query = dbSet.Include(includeExpression);
}
return query ?? dbSet;
}
My questions are:
Q1. When I use Include the related entities (PierFoundation, PierCap, PierColumn), I don't get them all!. So, when I type:
PierFoundations = CurrentUnitOfWork.PierFoundationRepository.Include(x => x.PierColumns, x => x.PierCaps);
I received just PierFoundation and PierCap, but not PierColumn
What is the wrong here?. I want to retrieve all data in the all three of them.
Q2. In the Project class, I have four calculate fields:
BridgeCount which is solved by Bridges.Count
PierFoundationCount
PierCapCount
PierColumnCount
The last three, I don't know how to get them, because they don't have direct relation with Project
BTW: I am using EF Core 2
Upvotes: 1
Views: 1233
Reputation: 205629
The two issues are unrelated, so answering only the main (as indicated by the post title) Q1:
When I use Include the related entities (PierFoundation, PierCap, PierColumn), I don't get them all!.
It's caused by the following line in your repository method implementation:
query = dbSet.Include(includeExpression);
As with many LINQ method, it's important to use the Include
method return value when chaining with other calls, and as you can see, this code stores only the last Include
call, hence the behavior you are observing.
It can be fixed by changing the implementation like this:
var query = Context.Set<TEntity>().AsQueryable();
foreach (var includeExpression in includeExpressions)
query = query.Include(includeExpression); // Note the usage of query variable
return query;
or simply
return includeExpresions.Aggregate(Context.Set<T>().AsQueryable(), (q, e) => q.Include(e));
But note that EF Core uses different approach for including nested data levels (ThenInclude
) which cannot be expressed with Expression<Func<T, object>>
, so you might consider exposing IQueryable<TEntity>
returning method from your repository and use the EF Core provided Include
/ ThenInclude
extension methods.
What about Q2, consider posting it in a separate SO question (post).
Upvotes: 3