C# 在OData中评估IQueryable后,如何填充模型中的某些属性?

C# 在OData中评估IQueryable后,如何填充模型中的某些属性?,c#,.net,entity-framework,asp.net-web-api,odata,C#,.net,Entity Framework,Asp.net Web Api,Odata,我将OData与实体框架一起使用。假设我有以下模型和控制器方法: public class Model1 { public int Id { get; set; } public int Field2 { get; set; } public int FieldFromOtherService { get; set; } public Model2 Model2 { get; set; } // Navigation Property public int

我将OData与实体框架一起使用。假设我有以下模型和控制器方法:

public class Model1
{
    public int Id { get; set; }
    public int Field2 { get; set; }
    public int FieldFromOtherService { get; set; }
    public Model2 Model2 { get; set; } // Navigation Property
    public int Model2Id { get; set; }
}

public class Model2
{
    public int Id { get; set; }
    public int Field { get; set; }
}


[HttpGet, EnableQuery]
public IQueryable<Model1> Get()
{
    return modelRepository.List();
}
公共类模型1
{
公共int Id{get;set;}
公共int字段2{get;set;}
public int FieldFromOtherService{get;set;}
公共Model2 Model2{get;set;}//导航属性
公共int Model2Id{get;set;}
}
公共类模型2
{
公共int Id{get;set;}
公共整型字段{get;set;}
}
[HttpGet,EnableQuery]
公共IQueryable Get()
{
返回modelRepository.List();
}
Model1
的属性
FieldFromOtherService
不是从DB中获取的,而是从其他服务中检索的。我需要一种在应用OData top、skip、EXPLAND和select子句后填充此属性的方法


有没有办法做到这一点?我曾尝试为
IQueryable
做一个包装,并在评估后调用操作,但当查询更复杂时,它会崩溃。

最后,我通过@zaitsman建议实现了我的目标。这比我想象的更难,因为OData添加了不可访问的包装(类
SelectAllAndExpand
SelectAll
SelectSome和Inheritance
SelectSome
)。使用expand时,需要从包装器中提取DTO。我的代码大致如下所示:

[HttpGet]
public IHttpActionResult Get(ODataQueryOptions<Model1> options)
{
    var result = modelRepository.List();
    Action<ICollection<Model1>> postAction = collection => { Console.WriteLine("Post Action"); };
    return ApplyOdataOptionsAndCallPostAction(result, options, postAction);
}

private IHttpActionResult ApplyOdataOptionsAndCallPostAction<T>(
    IQueryable<T> baseQuery, 
    ODataQueryOptions<T> options, 
    Action<ICollection<T>> postAction)
    where T : class
{
    var queryable = options.ApplyTo(baseQuery);
    var itemType = queryable.GetType().GetGenericArguments().First();
    var evaluatedQuery = ToTypedList(queryable, itemType);

    var dtos = ExtractAllDtoObjects<T>(evaluatedQuery).ToList();
    postAction(dtos)

    return Ok(evaluatedQuery, evaluatedQuery.GetType());
}

private static IList ToTypedList(IEnumerable self, Type innerType)
{
    var methodInfo = typeof(Enumerable).GetMethod(nameof(Enumerable.ToList));
    var genericMethod = methodInfo.MakeGenericMethod(innerType);
    return genericMethod.Invoke(null, new object[]
    {
        self
    }) as IList;
}

private IEnumerable<T> ExtractAllDtoObjects<T>(IEnumerable enumerable)
    where T : class
{
    foreach (var item in enumerable)
    {
        if (item is T typetItem)
        {
            yield return typetItem;
        }
        else
        {
            var result = TryExtractTFromWrapper<T>(item);
            if (result != null)
            {
                yield return result;
            }
        }
    }
}

private static T TryExtractTFromWrapper<T>(object item)
    where T : class
{
    if (item is ISelectExpandWrapper wrapper)
    {
        var property = item.GetType().GetProperty("Instance");
        var instance = property.GetValue(item);
        if (instance is T val)
        {
            return val;
        }
    }

    return null;
}

private IHttpActionResult Ok(object content, Type type)
{
    var resultType = typeof(OkNegotiatedContentResult<>).MakeGenericType(type);
    return Activator.CreateInstance(resultType, content, this) as IHttpActionResult;
}
[HttpGet]
公共IHttpActionResult获取(ODataQueryOptions选项)
{
var result=modelRepository.List();
Action postAction=collection=>{Console.WriteLine(“Post Action”);};
返回ApplyDataOptions和CallPostAction(结果、选项、postAction);
}
私有IHttpActionResult应用数据选项和CallPostAction(
IQueryable baseQuery,
ODataQueryOptions选项,
行动(邮购)
T:在哪里上课
{
var queryable=options.ApplyTo(baseQuery);
var itemType=queryable.GetType().GetGenericArguments().First();
var evaluatedQuery=ToTypedList(可查询,itemType);
var dtos=ExtractAllDtoObjects(evaluatedQuery).ToList();
邮递服务(dtos)
返回Ok(evaluatedQuery,evaluatedQuery.GetType());
}
私有静态IList ToTypedList(IEnumerable self,类型innerType)
{
var methodInfo=typeof(Enumerable.GetMethod)(nameof(Enumerable.ToList));
var genericMethod=methodInfo.MakeGenericMethod(innerType);
返回genericMethod.Invoke(null,新对象[])
{
自己
})作为IList;
}
私有IEnumerable ExtractAlldToObject(IEnumerable enumerable)
T:在哪里上课
{
foreach(可枚举中的变量项)
{
if(项目为T型)
{
收益率-回报率;
}
其他的
{
var结果=tryExtractFromWrapper(项目);
如果(结果!=null)
{
收益结果;
}
}
}
}
私有静态T TryExtractFromWrapper(对象项)
T:在哪里上课
{
如果(项目为ISelectExpandWrapper)
{
var property=item.GetType().GetProperty(“实例”);
var实例=property.GetValue(项);
if(实例为T val)
{
返回val;
}
}
返回null;
}
私有IHttpActionResult Ok(对象内容,类型)
{
var resultType=typeof(OkNegotiatedContentResult)。MakeGenericType(type);
将Activator.CreateInstance(resultType,content,this)作为IHttpActionResult返回;
}

在操作中使用
ODataQueryOptions
作为参数,而不是
EnableQuery
。然后,执行将为您提供对象列表的
options.Apply(modelRepository.List()
,然后您可以
foreach
或以其他方式设置所需的属性