C#和EF无法将相关实体添加到模型中

时间:2015-01-03 13:38:28

标签: c# asp.net-mvc entity-framework

我想获得包含标签的帖子列表。

我有模型

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

我的代码到目前为止:

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

我在Object reference not set to an instance of an object行中得到.Select(bp => new BlogPostGetByUrlSlugDto

知道为什么吗?

_blogPostRepository.Query存储库是:

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

查询的实施:

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

    public virtual IQueryable<T> Query
    {
        get
        {
            return _dbSet;
        }
    }
}

3 个答案:

答案 0 :(得分:5)

要在主查询中加载实体(此过程称为eager loading),您可以使用Include() method并将集合作为表达式传递。

要使用Entity Framework的某些扩展,请记住添加以下命名空间:

using System.Data.Entity;

对于示例,请尝试以下方法:

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;

由于您调用ToListSingleFistOrDefault方法,因此会将查询执行到数据库中。在您的代码中,您调用ToList(),它将在数据库中执行查询并执行标记的每个查询(延迟加载)。

阅读本文以了解有关如何使用Earger / Lazy加载的更多信息。 http://msdn.microsoft.com/en-us/data/jj574232.aspx

答案 1 :(得分:1)

你应该能够使用.Include和IQueryable,但你应该添加

using System.Data.Entity;

因为它是一种IQueryable扩展方法。

方法规范: DbExtensions.Include Method


除此之外,您应该检查 BlogCategory是否为null ,如果您需要在Select中处理它,否则它将为null并在您尝试时抛出错误访问null对象的属性。

类似的东西:

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

答案 2 :(得分:1)

Tags中的BlogPostGetByUrlSlugDto集合更改为此(需要虚拟关键字):

public virtual ICollection<BlogTagGetByPostIdDto> Tags { get; set; }

这是延迟加载工作的必要条件。 BlogTagGetByPostIdDto类也需要主键,因此请将其更改为:

public class BlogTagGetByPostIdDto
{
    [Key]
    public string Name { get; set; }
    public string UrlSlug { get; set; }
}

如果您不希望name是唯一的,请为此类添加ID属性。 现在,当您检索到BlogPostGetByUrlSlugDto对象并使用Tags属性时,它将检索与此对象关联的标记。