0

我已经为我的通用 repo 实现了一个通用规范模式,但我不知道如何将 a 添加.ThenInclude()到代码中。
仅供参考 - 我有 3 个实体(User->PracticedStyles->YogaStyles),当我去取我的时候,User我想取YogaStyles他/她的所有练习(例如 bikram、vinyasa 等)。但是我无法获取YogaStyle实体,我可以获取所有PracticedStyle实体,User因为它只有一个实体深,但我不知道如何YogaStyle从每个实体中获取/包含实体PracticedStyle

我正在使用具有通用存储库模式的通用规范模式,并且我创建了一个中间表来保存所有样式,这可能是错误的,或者我不知道如何正确使用通用规范模式?

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

2 回答 2

0

我想出了我需要什么。按照这个链接 我需要添加

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(),但作为一系列字符串。

于 2020-09-20T08:10:29.160 回答
0

这是一个解决方案。使您的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, TAnother> ThenInclude<TAnother>(Expression<Func<TTo, IEnumerable<TAnother>>> collectionIncludeExpression);
}

适当地实现这个接口。实现应该是围绕单个“包含”表达式的包装器。您可能需要两种实现:一种用于包装集合包含,另一种用于简单对象包含。

class的Includes属性BaseSpecification应该是这个接口的一个集合。

在你的,递归SpecificationEvaluator处理你的Includes,以及ThenIncludes他们可能拥有的所有东西。

我知道它有很多代码,但恐怕没有其他方法:)

于 2020-09-20T06:36:36.297 回答