问题描述
我已经为通用仓库实现了通用规范模式,但是我不知道如何在代码中添加.ThenInclude()
。
仅供参考-我有3个实体(User->PracticedStyles->YogaStyles
),当我去获取我的User
时,我想获取他/她实践的所有YogaStyles
(例如bikram,vinyasa等)。但是我无法获取YogaStyle
实体,我可以获取PracticedStyle
的所有User
实体,因为它只是一个实体,但我不知道如何获取/包括每个YogaStyle
中的PracticedStyle
实体。
我正在使用带有通用存储库模式的通用规范模式,并且已经创建了一个包含所有样式的中间表,也许这是错误的,或者我不知道如何正确使用通用规范模式? / p>
public class User : IdentityUser<int>
{
public ICollection<PracticedStyle> PracticedStyles { get; set; }
}
public class PracticedStyle : BaseEntity
{
public int UserId { get; set; }
public User User { get; set; }
public int YogaStyleId { get; set; }
public YogaStyle YogaStyle { get; set; }
}
public class YogaStyle : BaseEntity
{
public string Name { get; set; } // strength,vinyasa,bikram,etc
}
[HttpGet("{id}",Name = "GetMember")]
public async Task<IActionResult> GetMember(int id)
{
var spec = new MembersWithTypesspecification(id);
var user = await _membersRepo.GetEntityWithSpec(spec);
if (user == null) return NotFound(new ApiResponse(404));
var userToReturn = _mapper.Map<MemberForDetailDto>(user);
return Ok(userToReturn);
}
public class MembersWithTypesspecification : BaseSpecification<User>
{
public MembersWithTypesspecification(int id)
: base(x => x.Id == id)
{
AddInclude(x => x.UserPhotos);
AddInclude(x => x.Experience);
AddInclude(x => x.Membership);
AddInclude(x => x.PracticedStyles);
// doesn't work - yogastyles is not a collection
// AddInclude(x => x.PracticedStyles.YogaStyles);
AddInclude(x => x.InstructedStyles);
}
}
这是BaseSpecification中的“ AddInclude”
public class BaseSpecification<T> : ISpecification<T>
{
public BaseSpecification()
{
}
public BaseSpecification(Expression<Func<T,bool>> criteria)
{
Criteria = criteria;
}
public List<Expression<Func<T,object>>> Includes { get; } = new List<Expression<Func<T,object>>>();
protected void AddInclude(Expression<Func<T,object>> includeExpression)
{
Includes.Add(includeExpression);
}
}
这是getEntityWithSpec
public async Task<T> GetEntityWithSpec(ISpecification<T> spec)
{
return await ApplySpecification(spec).FirstOrDefaultAsync();
}
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
{
return SpecificationEvaluator<T>.GetQuery(_context.Set<T>().AsQueryable(),spec);
}
和规格评估者
public class SpecificationEvaluator<TEntity> where TEntity : class // BaseEntity // when using BaseEntity,we constrain it to on base entities
{
public static IQueryable<TEntity> GetQuery(IQueryable<TEntity> inputQuery,ISpecification<TEntity> spec)
{
var query = inputQuery;
if (spec.Criteria != null)
{
query = query.Where(spec.Criteria); // e => e.YogaEventTypeId == id
}
if (spec.OrderBy != null)
{
query = query.OrderBy(spec.OrderBy);
}
if (spec.OrderByDescending != null)
{
query = query.OrderByDescending(spec.OrderByDescending);
}
if (spec.IsPagingEnabled)
{
query = query.Skip(spec.Skip).Take(spec.Take);
}
query = spec.Includes.Aggregate(query,(current,include) => current.Include(include)); // 'current' represents entity
return query;
}
}
解决方法
这是一个解决方案。让您的AddInclude
方法返回类似ISpecificationInclude
的内容:
public interface ISpecificationInclude<TFrom,TTo>
where TFrom : IEntity
where TTo : IEntity
// I know that you do not have a `IEntity` interface,but I advise you to
// add it to your infrastructure and implement it by all your entity classes.
{
ISpecificationInclude<TTo,TAnother> ThenInclude<TAnother>(Expression<Func<TTo,TAnother>> includeExpression);
ISpecificationInclude<TTo,IEnumerable<TAnother>>> collectionIncludeExpression);
}
适当地实现此接口。该实现应该是单个“ include”表达式的包装。您可能需要两种实现:一种用于包装集合包含,另一种用于简单对象包含。
Includes
类的BaseSpecification
属性应该是此接口的集合。
在您的SpecificationEvaluator
中,递归处理您的Includes
及其所有ThenIncludes
。
我知道有很多代码,但是恐怕别无他法了:)
,我知道了我需要什么。 遵循此link 我需要添加
AddInclude($"{nameof(User.PracticedStyles)}.{nameof(PracticedStyle.YogaStyle)}");
和
query = specification.IncludeStrings.Aggregate(query,(current,include) => current.Include(include));
和
public List<string> IncludeStrings { get; } = new List<string>();
protected virtual void AddInclude(string includeString)
{
IncludeStrings.Add(includeString);
}
这使我可以使用.thenInclude(),但可以用作一系列字符串。