将 Linq 表达式转换为 QueryExpression 或 FetchXML

发布于 2024-11-25 05:08:34 字数 430 浏览 3 评论 0原文

我的最终目标是将 linq 表达式转换为获取 xml。我打算在 MS CRM 2011 中将 fetch XML 用于自定义网格。

通过本文,我可以将 QueryExpression 转换为 FetchXML http://mileyja.blogspot.com/2011/07/convert-queryexpression-to-fetchxml.html

但我不知道如何将 Linq 表达式获取到 QueryExpression。当我说 linq 表达式时,我指的是 IQueryable<> 类型的对象。

有人有这方面的经验或知道如何做吗?

干杯

My ultimate goal is to convert a linq expression to fetch xml. I intend on using the fetch XML for custom grids in MS CRM 2011.

From this article, I can convert a QueryExpression to FetchXML http://mileyja.blogspot.com/2011/07/convert-queryexpression-to-fetchxml.html

But I don't know how to get a Linq expression to a QueryExpression. When I say a linq expression, I mean an object of type IQueryable<>.

Anyone had any experience with this or any know how?

Cheers

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

昨迟人 2024-12-02 05:08:34

正如 Chielus 提到的,所提供的解决方案不适用于 CRM2013 SDK 程序集。

对于 CRM2013,您可以使用此扩展方法:

public static class QueryProviderExtensions
{
    public static QueryExpression ToQueryExpression<T>(this IQueryable<T> items)
    {
        var queryProvider = items.Provider;

        var queryProviderType = queryProvider.GetType();
        var listType = typeof(List<>);

        var projectionType = queryProviderType.Assembly.GetType("Microsoft.Xrm.Sdk.Linq.QueryProvider+Projection");
        var navigationSourceType = queryProviderType.Assembly.GetType("Microsoft.Xrm.Sdk.Linq.QueryProvider+NavigationSource");
        var linkLookupType = queryProviderType.Assembly.GetType("Microsoft.Xrm.Sdk.Linq.QueryProvider+LinkLookup");
        var linkLookupListType = listType.MakeGenericType(linkLookupType);

        object projection = null;
        object source = Activator.CreateInstance(navigationSourceType, new object[] { null, null });
        object linkLookups = Activator.CreateInstance(linkLookupListType);
        bool throwIfSequenceIsEmpty = false;
        bool throwIfSequenceNotSingle = false;

        object[] arguments = new object[6];
        arguments[0] = items.Expression;
        arguments[1] = throwIfSequenceIsEmpty;
        arguments[2] = throwIfSequenceNotSingle;
        arguments[3] = projection;
        arguments[4] = source;
        arguments[5] = linkLookups;

        var getQueryExpressionMethod = queryProviderType.GetMethod("GetQueryExpression", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new[] {
                typeof(Expression), 
                typeof(bool).MakeByRefType(), 
                typeof(bool).MakeByRefType(),
                projectionType.MakeByRefType(),
                navigationSourceType.MakeByRefType(),
                linkLookupListType.MakeByRefType(),
            }, null);

        var queryExpression = (QueryExpression)getQueryExpressionMethod.Invoke(queryProvider, arguments);
        return queryExpression;
    }

    public static string ToXml(this QueryExpression queryExpression, IOrganizationService service)
    {
        var request = new QueryExpressionToFetchXmlRequest { Query = queryExpression };
        var response = (QueryExpressionToFetchXmlResponse)service.Execute(request);
        return response.FetchXml;
    }
}

像这样使用它:

    // This can be any query
    var query = (from e in contactSet.Query()
                 where e.LastName.Contains("e")
                 select e);

    // This is where the magic happens
    var queryExpression = query.ToQueryExpression();

    // We can now add paging info
    queryExpression.PageInfo = new PagingInfo()
    {
        PageNumber = 1,
        Count = 50,
        ReturnTotalRecordCount = true
    };

    // This will create a QueryExpressionToFetchXmlRequest, not needed for paging.
    var xml = queryExpression.ToXml(service);

    // Perform the actual request 
    var collection = service.RetrieveMultiple(queryExpression);

此处有更多详细信息:

https://social.msdn.microsoft.com/Forums/en-US/0026f1de-bc10-428d-ad15-18d34315c814/convert-linq-query-to-fetchxml-sdk-2013?forum=crm

The provided solution does not work for CRM2013 SDK assemblies as mentioned by Chielus.

For CRM2013 you can use this extension method:

public static class QueryProviderExtensions
{
    public static QueryExpression ToQueryExpression<T>(this IQueryable<T> items)
    {
        var queryProvider = items.Provider;

        var queryProviderType = queryProvider.GetType();
        var listType = typeof(List<>);

        var projectionType = queryProviderType.Assembly.GetType("Microsoft.Xrm.Sdk.Linq.QueryProvider+Projection");
        var navigationSourceType = queryProviderType.Assembly.GetType("Microsoft.Xrm.Sdk.Linq.QueryProvider+NavigationSource");
        var linkLookupType = queryProviderType.Assembly.GetType("Microsoft.Xrm.Sdk.Linq.QueryProvider+LinkLookup");
        var linkLookupListType = listType.MakeGenericType(linkLookupType);

        object projection = null;
        object source = Activator.CreateInstance(navigationSourceType, new object[] { null, null });
        object linkLookups = Activator.CreateInstance(linkLookupListType);
        bool throwIfSequenceIsEmpty = false;
        bool throwIfSequenceNotSingle = false;

        object[] arguments = new object[6];
        arguments[0] = items.Expression;
        arguments[1] = throwIfSequenceIsEmpty;
        arguments[2] = throwIfSequenceNotSingle;
        arguments[3] = projection;
        arguments[4] = source;
        arguments[5] = linkLookups;

        var getQueryExpressionMethod = queryProviderType.GetMethod("GetQueryExpression", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new[] {
                typeof(Expression), 
                typeof(bool).MakeByRefType(), 
                typeof(bool).MakeByRefType(),
                projectionType.MakeByRefType(),
                navigationSourceType.MakeByRefType(),
                linkLookupListType.MakeByRefType(),
            }, null);

        var queryExpression = (QueryExpression)getQueryExpressionMethod.Invoke(queryProvider, arguments);
        return queryExpression;
    }

    public static string ToXml(this QueryExpression queryExpression, IOrganizationService service)
    {
        var request = new QueryExpressionToFetchXmlRequest { Query = queryExpression };
        var response = (QueryExpressionToFetchXmlResponse)service.Execute(request);
        return response.FetchXml;
    }
}

Use it like so:

    // This can be any query
    var query = (from e in contactSet.Query()
                 where e.LastName.Contains("e")
                 select e);

    // This is where the magic happens
    var queryExpression = query.ToQueryExpression();

    // We can now add paging info
    queryExpression.PageInfo = new PagingInfo()
    {
        PageNumber = 1,
        Count = 50,
        ReturnTotalRecordCount = true
    };

    // This will create a QueryExpressionToFetchXmlRequest, not needed for paging.
    var xml = queryExpression.ToXml(service);

    // Perform the actual request 
    var collection = service.RetrieveMultiple(queryExpression);

More details here:

https://social.msdn.microsoft.com/Forums/en-US/0026f1de-bc10-428d-ad15-18d34315c814/convert-linq-query-to-fetchxml-sdk-2013?forum=crm

百思不得你姐 2024-12-02 05:08:34

您可以使用反射来获取 QueryExpression,从 IQuerable 获取提供程序并对其调用 Translate 方法。

这是我正在使用的扩展方法:

public static QueryExpression ToQueryExpression(this IQueryable @this)
{
    var provider = @this.Provider;
    var translateMethod = provider.GetType().GetMethod("Translate");
    var query = (QueryExpression)translateMethod.Invoke(provider, new object[] { @this.Expression });

    return query;
}

如果您在 C# 中使用某种动态包装器进行反射,例如 ExposedObject 您可以这样做:

public static QueryExpression ToQueryExpression(this IQueryable @this)
{
    dynamic provider = ExposedObject.From(@this.Provider);

    return provider.Translate(@this.Expression);
}

对于 fetch,您需要有 QueryExpression,然后发出一个返回 QueryExpressionToFetchXmlResponse 的请求 QueryExpressionToFetchXmlRequest响应,其具有属性 FetchXml

you can use reflection to get QueryExpression, from IQuerable<T> get the provider and call Translate method on it.

here is extension method I'm using:

public static QueryExpression ToQueryExpression(this IQueryable @this)
{
    var provider = @this.Provider;
    var translateMethod = provider.GetType().GetMethod("Translate");
    var query = (QueryExpression)translateMethod.Invoke(provider, new object[] { @this.Expression });

    return query;
}

if you use some sort of dynamic wrapper for reflection in C# like ExposedObject you can just do smth like that:

public static QueryExpression ToQueryExpression(this IQueryable @this)
{
    dynamic provider = ExposedObject.From(@this.Provider);

    return provider.Translate(@this.Expression);
}

as for fetch you need to have QueryExpression and then issue a request QueryExpressionToFetchXmlRequest that returns QueryExpressionToFetchXmlResponse response, which have property FetchXml.

就此别过 2024-12-02 05:08:34

对 LINQ 表达式调用 ToString() 应返回 FetchXML

calling ToString() on the LINQ expression should return the FetchXML

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文