【问题标题】:How to fill some properties in model after evaluation of IQueryable in OData?在 OData 中评估 IQueryable 后如何在模型中填充一些属性?
【发布时间】:2017-11-03 10:58:24
【问题描述】:

我将 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();
}

Model1 有属性FieldFromOtherService 不是从数据库中获取的——它是从其他服务中检索的。在应用 OData top、skip、expand 和 select 子句后,我需要一种方法来填充此属性。

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

【问题讨论】:

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

标签: c# .net entity-framework asp.net-web-api odata


【解决方案1】:

最后,我通过@zaitsman 的建议设法实现了我的目标。这比我想的要难,因为 OData 添加了无法访问的包装器(类SelectAllAndExpandSelectAllSelectSomeAndInheritanceSelectSome)。使用扩展时,需要从包装器中提取 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多