问题
I'm trying to do basic eager loading on a list of ProjectVersions where each ProjectVersion has a list of FieldValues and ChildProjects. I want the FieldValues and ChildProjects to be loaded along with all their properties when ProjectVersions is loaded, but it seems that in my code when going through each ProjectVersion, it still hits the database to get these collections (checking sql server profiler). Any pointers would be helpful.
var publishedList = Repository.Find<Project>().//a bunch of wheres and selects
IEnumerable<ProjectVersion> publishedList = published
.Include(x => x.FieldValues)
.Include(x => x.ChildProjects)
.ToList();
//EDIT: the context is hidden behind a generic Repository. Below are some details:
public class Repository : IRepository
{
internal readonly IDataContext _context;
public Repository(IDataContext context)
{
_context = context;
_context.Committed += _context_Committed;
_context.Deleted += _context_Deleted;
}
public IQueryable<T> Find<T>() where T : class, IEntity
{
return _context.Repository<T>();
}
}
public class EfDataContext : IDataContext
{
public IQueryable<T> Repository<T>() where T : class, IEntity
{
var table = _context.Set(typeof(T));
WrappedFieldsObjectQuery<T>(table.Cast<T>().AsExpandable()));
return table.Cast<T>().AsExpandable();
}
}
public class MsmDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type =>
type.IsClass &&
type.BaseType.IsGenericType &&
type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var config in typesToRegister.Select(Activator.CreateInstance))
{
modelBuilder.Configurations.Add((dynamic)config);
}
base.OnModelCreating(modelBuilder);
}
}
public class ProjectMapping : EntityTypeConfiguration<Project>
{
public ProjectMapping()
{
HasOptional(p => p.LastChangedBy).WithMany(p => p.ProjectsChanged).WillCascadeOnDelete();
HasRequired(p => p.CreatedBy).WithMany(p => p.ProjectsCreated).WillCascadeOnDelete();
HasRequired(d => d.Account).WithMany(p => p.Projects).WillCascadeOnDelete();
HasRequired(d => d.PinType).WithMany(p => p.Projects).HasForeignKey(p => p.PinType_Id).WillCascadeOnDelete();
}
}
public static class RepositoryFactory
{
public static IRepository CreateRepository()
{
return CreateEfRepository();
}
internal static IRepository CreateEfRepository()
{
return new Repository(new EfDataContext(new MsmDbContext()));
}
}
回答1:
Ok, I can't see your complete query, but in your comments you wrote something about select. EF will ignore Include() statements as soon as you are doing custom projections using Select(), my guess is that's why eager loading does not work. Instead of Include(), try to add the properties you want to load to your projection, something like
Repository.Find<Project>()
.Select(p => new { project = p, p.FieldValues, p.ChildProjects })
.AsEnumerable().Select(p => p.project).ToList()
This way the projection will take care of loading your data, you don't need Include().
回答2:
Actually, I got it to work by just directly working with the DataContext. Somehow the Repository is screwing it up.
来源:https://stackoverflow.com/questions/37863860/why-isnt-eager-loading-working-in-entity-framework