我正在研究一个支持本地化实体的项目。 目前,我具有以下结构:
实体:
public class Role : LocalizableEntity<RoleTranslation, Role, int>, IEntity<int>
{
[Required]
[MaxLength(150)]
public string Code { get; set; }
[LocalizableProperty]
[Required]
[MaxLength(150)]
public string Name { get; set; }
[LocalizableProperty]
[MaxLength(500)]
public string Description { get; set; }
public bool Active { get; set; }
public virtual ICollection<RolePermission> Permissions { get; set; }
public virtual ICollection<RoleTranslation> Translations { get; set; }
}
public class RoleTranslation : TranslationEntity<Role, int>, ITranslationEntity<Role, int>
{
[Required]
[MaxLength(150)]
public string Name { get; set; }
[MaxLength(500)]
public string Description { get; set; }
public virtual Permission OwnerEntity { get; set; }
public int OwnerEntityId { get; set; }
public int LanguageId { get; set; }
public virtual Language Language { get; set; }
}
public class Permission : LocalizableEntity<PermissionTranslation, Permission, int>, IEntity<int>
{
[Required]
[MaxLength(150)]
public string Code { get; set; }
[LocalizableProperty]
[Required]
[MaxLength(250)]
public string Name { get; set; }
[LocalizableProperty]
[MaxLength(500)]
public string Description { get; set; }
public virtual ICollection<PermissionTranslation> Translations { get; set; }
}
public class PermissionTranslation : TranslationEntity<Permission, int>, ITranslationEntity<Permission, int>
{
[Required]
[MaxLength(250)]
public string Name { get; set; }
[MaxLength(500)]
public string Description { get; set; }
public virtual Role OwnerEntity { get; set; }
public int OwnerEntityId { get; set; }
public int LanguageId { get; set; }
public virtual Language Language { get; set; }
}
public class RolePermission : Entity<int>
{
public int RoleId { get; set; }
public Role Role { get; set; }
public int PermissionId { get; set; }
public Permission Permission { get; set; }
}
标记为[LocalizableProperty]的属性未映射到数据库。仅在此处用于只读目的。
Dto:
public class RoleDTO : IDTO
{
public int Id { get; set; }
public string Description { get; set; }
public IEnumerable<PermissionBO> Permissions { get; set; }
public static Expression<Func<Role, RoleDTO>> Projection
{
get
{
return x => new RoleDTO()
{
Id = x.Id,
Description = x.Description,
Permissions = x.RolePermissions.AsQueryable().Select(y => y.Permission).Select(PermissionDTO.Projection).ToList()
};
}
}
}
public class PermissionDTO : IDTO
{
public int Id { get; set; }
public string Name { get; set; }
public static Expression<Func<Permission, PermissionDTO>> Projection
{
get
{
return x => new PermissionDTO()
{
Id = x.Id,
Name = x.Name
};
}
}
}
每个DTO都有一个仅选择数据库上所需列的投影。
在存储库中,我正在对翻译实体表执行查询,并使用Navigation属性返回所有者实体:
IQueryable<TTranslationEntity> queryableResult = _translationEntities
.Include(x => x.OwnerEntity)
.Where(x => x.Language.Name == options.LanguageName)
.AsQueryable();
// Projection
var projectionExpression = MyParameterReplacer.Convert(options.Projection);
IQueryable<TResult> projection = queryableResult.Select(projectionExpression);
我想做的是,在进行投影之前,使用自定义ExpressionVisitor重建给定的投影,并替换所有参数和成员以对应于目标IQueryable。 表达式中的主实体中的属性必须为x.OwnerEntity.PropertyName,表达式中的平移实体中的属性必须为x.PropertyName
目前,我有这个问题,但是问题是嵌套表达式没有被正确访问。
private class MyExpressionVisitor<TOwnerEntity, TTranslationEntity> : ExpressionVisitor
{
private ReadOnlyCollection<ParameterExpression> _parameters;
protected override Expression VisitParameter(ParameterExpression node)
{
return (_parameters != null)
? _parameters.FirstOrDefault(p => p.Name == node.Name)
: (node.Type.GetInterfaces().Any(x => x == typeof(TOwnerEntity)) ? Expression.Parameter(typeof(TTranslationEntity), node.Name) : node);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
_parameters = VisitAndConvert<ParameterExpression>(node.Parameters, "VisitLambda");
return Expression.Lambda(Visit(node.Body), _parameters);
}
protected override Expression VisitMember(MemberExpression node)
{
return base.VisitMember(node);
if (node.Member.DeclaringType == typeof(TOwnerEntity))
{
var targetParameter = _parameters.FirstOrDefault(x => x.Type == typeof(TTranslationEntity));
var ownerEntityProperty = typeof(TTranslationEntity).GetProperty("OwnerEntity"));
var memberOnOwnerEntity = ownerEntityProperty.PropertyType.GetProperty(node.Member.Name);
var memberOnTranslations = typeof(TTranslationEntity).GetProperty(node.Member.Name);
if (memberOnTranslations is null && ownerEntityProperty != null && memberOnOwnerEntity != null)
{
var ownerEntityPropertyExpression = Expression.Property(targetParameter, ownerEntityProperty);
return Expression.MakeMemberAccess(Visit(ownerEntityPropertyExpression), memberOnOwnerEntity);
}
else
{
return Expression.MakeMemberAccess(Visit(node.Expression), memberOnTranslations);
}
}
return base.VisitMember(node);
}
}
}
谢谢