使用Simple.OData.Client动态语法将项目投影到已知类型

时间:2019-09-16 23:03:51

标签: .net-core odata simple.odata

Simple.OData.Client具有类型化的动态(和基本)语法。

我喜欢键入的内容,但我不想建立所有的类型。最后,我实际上只需要两种或两种类型的结果即可。

但是我的查询需要更多类型才能正确过滤结果。

所以我想使用动态语法。但是我想将结果投射到我拥有的类中。

我可以轻松地手动完成此操作,但是我想在为每个查询编写所有转换代码之前,先看看Simple.OData.Client是否支持此操作。

以下是一些运行时不会出错的动态语法代码:

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

这是我希望可以工作的一个示例(选择一个新的Client对象)

client.For(x.Client).Top(10).Select(x.ClientId, x.Name).FindEntriesAsync();

但是不支持这种投影(我收到“有一些无效的参数”错误)。

使用Simple.OData.Client的动态语法时,是否有一种方法可以支持投射到现有类中?

1 个答案:

答案 0 :(得分:0)

编辑:以下代码有效。但是它的表现很糟糕。我决定放弃它,为我需要的每种类型编写手写的映射器。

这是我想出的:

dynamic results = oDataClient.For(x.Client).Select(x.ClientId, x.Name).FindEntriesAsync().Result;   
var listOfClients = SimpleODataToList<Client>(results);


public List<T> SimpleODataToList<T>(dynamic sourceObjects) where T : new()
{
    List<T> targetList = new List<T>();

    foreach (var sourceObject in sourceObjects)
    {
        // This is a dictionary with keys (properties) and values.  But no 
        //  matter what sourceObject is passed in, the values will always be
        //  the values of the first entry in the sourceObjects list.
        var sourceProperties = ((System.Collections.Generic.IDictionary<string, object>)sourceObject);  

        var targetProperties = typeof(Client).GetProperties().Where(prop => prop.CanWrite);

        var targetObject = new T();

        foreach (var targetProperty in targetProperties)
        {
            if (sourceProperties.ContainsKey(targetProperty.Name))
            {

                var sourceValue = GetProperty(sourceObject, targetProperty.Name);
                targetProperty.SetValue(targetObject, sourceValue, null);
            }               
        }   
        targetList.Add(targetObject);
    }
    return targetList;
}

public static object GetProperty(object o, string member)
{
    if (o == null) throw new ArgumentNullException("o");
    if (member == null) throw new ArgumentNullException("member");
    Type scope = o.GetType();
    IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
    if (provider != null)
    {
        ParameterExpression param = Expression.Parameter(typeof(object));
        DynamicMetaObject mobj = provider.GetMetaObject(param);
        GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) });
        DynamicMetaObject ret = mobj.BindGetMember(binder);
        BlockExpression final = Expression.Block(
            Expression.Label(CallSiteBinder.UpdateLabel),
            ret.Expression
        );
        LambdaExpression lambda = Expression.Lambda(final, param);
        Delegate del = lambda.Compile();
        return del.DynamicInvoke(o);
    }
    else
    {
        return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
    }
}

这样做变得更加困难,因为普通的转换以及返回的动态对象之类的东西只会一次又一次地给出列表中的第一个对象。 GetProperty方法可解决此限制。