我想获得包含标签的帖子列表。
我有模型:
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;
}
}
}
答案 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;
由于您调用ToList
或Single
或FistOrDefault
方法,因此会将查询执行到数据库中。在您的代码中,您调用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
属性时,它将检索与此对象关联的标记。