简体   繁体   中英

How can I know if related data is included when using eager loading in Entity Framework?

I'am working on a project that is using Repository pattern. We are using a Entity Framework to retrieve data from the database.To Load related data we use Eager loading which means that we have to explicitly include related data.

Say that we want to have all blogs and their related posts we would have to write: _dbContext.Blogs.include(b => b.Posts) .

The disadvantages with this is that you can only see which related data is loaded in the repository class.

I have tried to shown an example below. Here the problem occurs in the class BlogViewModel.cs because you try to access blogs.Posts , but posts is not included in the original query. So if you are trying to get related data, one would have to check the origin of query and see if it is included.

Repostiory.cs

  public IEnumerable<BlogDbModel> GetBlogs()
    {

        return _dbContext.Blogs.ToList();
    }

Service.cs

public IEnumerable<BlogViewModel> GetBlogs() {
  return _repository.Select(x => new BlogViewModel(x));
 }

BlogViewModel.cs

public class BlogViewModel {
  public BlogViewModel(BlogDbModel blogDbModel) {
    Name = blogDbModel.Name;
    Posts = blogDbModel.Posts;
}

  public string Name { get; set;}

  public IEnumberable<Posts> Posts {get; set;}

}

Does anyone have a smart solution to this? Is it possible give an compilation error if you are trying to access data that is not included?

Two options that i have thought about is:

  1. Use Lazy loading instead.
  2. Always return IQueryable from repository

thanks

No you dont have any option to give compilation error on this context. Data either way are loaded in the run-time.

LazyLoading Assuming your displaying Blogs, Posts, Comments in view, So you need to load everything when the page load. When you enable lazyload and map properties that not been included in the data layer query it will load related entities

public BlogViewModel(BlogDbModel blogDbModel) 
{
  Name = blogDbModel.Name;
  Posts = blogDbModel.Posts;
 }

If you enable lazyload and do this post will be fetched using lazyload feature. What if post contains a reference to User or any other object it will load those too. When you need everything at first place its not recommended to use lazyload because it will additional round-trip to database.

IQueryable from repository

I would say IQueryable to a viewmodel is leaky abstraction. Ideally your data layer should be performing these. Providing IQuerable<BlogDbModel> to Viewmodel is like developer able to fetch 1Blogs=>Post=>User=>Accounts1 anything related from this.

IMHO I would write data layer methods which are needed for the view.

LazyloadingEnabled = false;

public IEnumerable<BlogDbModel> GetBlogs()
{

    return _dbContext.Blogs.ToList();
}

public IEnumerable<BlogDbModel> GetBlogsAndPosts()
{

  return _dbContext.Blogs.Include("Posts").ToList();
}

//This will fetch only what is needed (You can customize to get columns what is needed)
public IEnumerable<NewCustomDTO> GetBlogsAndPostCount()
{

   return _dbContext.Blogs.Select(x=> NewCustomDTO
   {
       BlogName = x.BlogName,
       Count = x.Posts.Count(),
   });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM