Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# and EF not able to add related entities to model

I would like to get a list of Posts including the Tags.

I have the Model:

public class BlogPostGetByUrlSlugDto
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Category { get; set; }
    public string Color { get; set; }
    public string UrlSlug { get; set; }
    public string Description { get; set; }
    public IList<BlogTagGetByPostIdDto> Tags { get; set; }
}

public class BlogTagGetByPostIdDto
{
    public string Name { get; set; }
    public string UrlSlug { get; set; }
}

My Code so far:

public BlogPostGetByUrlSlugDto GetByUrlSlug(string urlSlug)
{
    var blogPostQuery = _blogPostRepository.Query;

    return blogPostQuery
                .Where(b => b.UrlSlug.Equals(urlSlug))
                .ToList()
                .Select(bp => new BlogPostGetByUrlSlugDto 
                { 
                    Id = bp.Id, 
                    Title = bp.Title, 
                    Category = bp.BlogCategory.Name, 
                    Color = bp.BlogCategory.Color, 
                    UrlSlug = bp.UrlSlug, 
                    Description = bp.Description,
                    Tags = bp.BlogTags.Select(t => new BlogTagGetByPostIdDto 
                                        { 
                                            Name = t.Name, 
                                            UrlSlug = t.UrlSlug
                                        })
                                        .ToList() 
                })
                .Single();
}

I get Object reference not set to an instance of an object in the line .Select(bp => new BlogPostGetByUrlSlugDto.

Any idea why?

The Repository for _blogPostRepository.Query is:

public interface IRepository<T> where T : class
{
    T FindById(int id, bool asNoTracking = false);

    T FindSingle(Expression<Func<T, bool>> predicate = null, bool asNoTracking = false, params Expression<Func<T, object>>[] includes);

    IQueryable<T> Find(Expression<Func<T, bool>> predicate = null, bool asNoTracking = false, params Expression<Func<T, object>>[] includes);


    /// <summary> 
    /// Add entity to the repository 
    /// </summary> 
    /// <param name="entity">The entity to add</param> 
    void Add(T entity);

    /// <summary> 
    /// Attach entity to the repository 
    /// </summary> 
    /// <param name="entity">The entity to attach</param> 
    void Attach(T entity);

    bool Exists(T entity);

    /// <summary> 
    /// Updates entity within the repository 
    /// </summary> 
    /// <param name="entity">The entity to update</param> 
    void Update(T entity, bool partial = false);


    /// <summary> 
    /// Mark entity by id to be deleted within the repository 
    /// </summary> 
    /// <param name="entity">The entity to delete</param> 
    void Delete(object id);


    /// <summary> 
    /// Mark entity to be deleted within the repository 
    /// </summary> 
    /// <param name="entity">The entity to delete</param> 
    void Delete(T entity);


    /// <summary>
    /// Get an item matching the id
    /// </summary>
    T GetById(int id);

    /// <summary>
    /// Get an item or itens matching the Expression including opcional parameters 
    /// </summary>
    IList<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "");

    /// <summary>
    /// Get an item matching to prediate
    /// </summary>
    //T Get(Func<T, bool> predicate);


    /// <summary>
    /// Get all the itens matching to prediate
    /// </summary>
    IList<T> GetAll(Func<T, bool> predicate);


    ///// <summary>
    ///// Get all the element of this repository
    ///// </summary>
    ///// <returns>Entities list</returns>
    IList<T> GetAll();


    /// <summary>
    /// Allow to send Linq queries to the entity
    /// </summary>
    IQueryable<T> Query { get; }


    /// <summary>
    /// Saves the pending changes back into the DataContext.
    /// </summary>
    void Save();
}

Implementation of the Query:

public class Repository<T> : IRepository<T> where T : class
{
    protected DbContext _dataContext;
    protected DbSet<T> _dbSet;

    public virtual IQueryable<T> Query
    {
        get
        {
            return _dbSet;
        }
    }
}
like image 569
Patrick Avatar asked Jan 03 '15 13:01

Patrick


2 Answers

To load entities within the main query, (this process is called eager loading), you can use the Include() method and pass your collection as an expression.

To use some extensions of Entity Framework, remember to add the following namespace:

using System.Data.Entity;

For sample, try something like this:

var result = _blogPostRepository.Query
                               .Where(b => b.UrlSlug.Equals(urlSlug))
                               .Include(b => b.Tags) 
                               .Select(bp => new BlogPostGetByUrlSlugDto 
                                { 
                                    Id = bp.Id, 
                                    Title = bp.Title, 
                                    Category = bp.BlogCategory.Name, 
                                    Color = bp.BlogCategory.Color, 
                                    UrlSlug = bp.UrlSlug, 
                                    Description = bp.Description,
                                    Tags = bp.Tags.Select(t => new BlogTagGetByPostIdDto 
                                                        { 
                                                            Name = t.Name, 
                                                            UrlSlug = t.UrlSlug
                                                        })
                                })
                                .FirstOrDefault();

return result;

Since you call ToList or Single or FistOrDefault methods, it will execute the query into the database. In your code, you call the ToList() and it will execute the query in database and execute each query (lazy loading) for tags.

Read this article to know more about how to lead with Earger/Lazy loading. http://msdn.microsoft.com/en-us/data/jj574232.aspx

like image 142
Felipe Oriani Avatar answered Sep 30 '22 01:09

Felipe Oriani


You should be able to use .Include with IQueryable but you should add

using System.Data.Entity;

as it's an IQueryable extension method.

Method specification: DbExtensions.Include Method


Besides that, you should check if BlogCategory can be null, if that's the case you need to deal with it in your Select, otherwise it will be null and throw the error as you're trying to access a property of a null object.

Something like:

public BlogPostGetByUrlSlugDto GetByUrlSlug(string urlSlug)
{
    var blogPostQuery = _blogPostRepository.Query;

    return blogPostQuery
                .Where(b => b.UrlSlug.Equals(urlSlug))
                .Include(b => b.Tags)
                .Select(bp => new BlogPostGetByUrlSlugDto 
                { 
                    Id = bp.Id, 
                    Title = bp.Title, 
                    Category = bp.BlogCategory == null ? string.Empty : bp.BlogCategory.Name, 
                    Color = bp.BlogCategory == null ? string.Empty : bp.BlogCategory.Color, 
                    UrlSlug = bp.UrlSlug, 
                    Description = bp.Description,
                    Tags = bp.BlogTags.Select(t => new BlogTagGetByPostIdDto 
                                        { 
                                            Name = t.Name, 
                                            UrlSlug = t.UrlSlug
                                        })
                                        .ToList() 
                })
                .FirstOrDefault();
}
like image 26
Álvaro Menezes Avatar answered Sep 30 '22 01:09

Álvaro Menezes