正如標題所說,“如何投射TResultwhich can be an objector List<object>inside an Expression<Func<T,TResult?>?”
public Task ExplicitLoadAsync<TProperty>(T entity, Expression<Func<T, TProperty?>> propertyExpression) where TProperty : class
{
var typeOfProp = typeof(TProperty);
if (typeOfProp.IsInterface && typeOfProp.GetGenericTypeDefinition() == typeof(ICollection<>))
{
var collectionExpression = propertyExpression as Expression<Func<T, IEnumerable<TProperty>>>;
if (collectionExpression is not null)
{
return _dbContext.Entry(entity).Collection(collectionExpression).LoadAsync();
}
}
return _dbContext.Entry(entity).Reference(propertyExpression).LoadAsync();
}
collectionExpression將始終為空,問題是Reference()僅接受IEnumerable<TProperty>和多載是不可能的,因為它將始終使用方法 withTProperty而不是Expression<Func<T, IEnumerable<TProperty>>> propertyExpression
原因是演員陣容錯誤,因為它將IEnumerable<IEnumerable<...>>如何解決?
一種方法是使用兩個具有不同名稱的方法,但我想跳過它,因為這需要在整個代碼庫中進行更多重構。
uj5u.com熱心網友回復:
此解決方案基于Guru Stron 已洗掉的答案
public async Task ExplicitLoadAsync<T, TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> propertiesExpression) where T : class where TProperty : class
=> await _dbContext.Entry(entity).Collection(propertiesExpression).LoadAsync();
public async Task ExplicitLoadAsync<T, TProperty>(T entity, Expression<Func<T, TProperty?>> propertyExpression) where T : class where TProperty : class
=> await _dbContext.Entry(entity).Reference(propertyExpression).LoadAsync();
這里的訣竅是使用不同的引數名稱:
Expression<Func<T, IEnumerable<TProperty>>> propertiesExpressionExpression<Func<T, TProperty?>> propertyExpression
這使您能夠呼叫兩個多載
ExplicitLoadAsync<Entity, string>(enity, e => e.SingleString);
ExplicitLoadAsync<Entity, string>(enity, propertiesExpression: e => e.CollectionOfStrings);
uj5u.com熱心網友回復:
我只想發布另一個答案來解決我的問題,而不是從 Peter Csala 的答案中呼叫帶有引數名稱的方法。
public Task ExplicitLoadAsync<TProperty>(T entity, Expression<Func<T, TProperty?>> propertyExpression) where TProperty : class
{
var typeOfProp = typeof(TProperty);
if (typeOfProp.IsInterface && typeOfProp.GetGenericTypeDefinition() == typeof(ICollection<>))
{
var pathName = PropertyPath<T>.GetAsStr(propertyExpression);
return _dbContext.Entry(entity).Collection(pathName).LoadAsync();
}
return _dbContext.Entry(entity).Reference(propertyExpression).LoadAsync();
}
這是實用程式類:
public static class PropertyPath<TSource>
{
public static IReadOnlyList<MemberInfo> Get<TResult>(Expression<Func<TSource, TResult>> expression)
{
var visitor = new PropertyVisitor();
visitor.Visit(expression.Body);
visitor._path.Reverse();
return visitor._path;
}
public static string GetAsStr<TResult>(Expression<Func<TSource, TResult>> expression)
{
return string.Join(".", Get(expression).Select(p => p.Name));
}
private sealed class PropertyVisitor : ExpressionVisitor
{
internal readonly List<MemberInfo> _path = new();
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member is not PropertyInfo)
{
throw new ArgumentException("The path can only contain properties", nameof(node));
}
_path.Add(node.Member);
return base.VisitMember(node);
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/511203.html
