zoukankan      html  css  js  c++  java
  • [AX]AX2012 AIF(九):系统服务之Query service

    通过Query service可以查询AX的数据,又分静态查询、用户自定义查询和动态查询三种方式,下面以实例来演示如何使用这几种查询。和使用其他系统服务一样首先要在.net工程中添加查询服务的引用,WSDL地址在http://<servername>:8101/DynamicsAx/Services/QueryService。

    • 静态查询:它使用已经创建在AOT中的Query,通过QueryServiceClient.ExecuteStaticQuery()方法运行这个Query,返回以数据集表示的结果:
    using System;
    using System.Data;
    using System.Windows.Forms;
    using QueryServiceStaticTest.QueryServiceReference;
    
    namespace QueryServiceStaticTest
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                this.Load += new EventHandler(Form1_Load);
    
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                QueryServiceClient client = new QueryServiceClient();
    
                DataSet dataSet;
                Paging paging = null;
    
                // Create the binding source objects.
                BindingSource custBindingSource = new BindingSource();
                BindingSource custTransBindingSource = new BindingSource();
                BindingSource custTransOpenBindingSource = new BindingSource();
    
                // Set the grid datasources to binding source objects.
                dataGridView1.DataSource = custBindingSource;
                dataGridView2.DataSource = custTransBindingSource;
                dataGridView3.DataSource = custTransOpenBindingSource;
    
                // Call the CustTable query using the query service.
                dataSet = client.ExecuteStaticQuery("CustTable", ref paging);
    
                // Set the binding source data sources and data members.
                // CustTable_CustTrans and CustTrans_CustTransOpen are table relations
                // in the dataset.
                custBindingSource.DataSource = dataSet;
                custBindingSource.DataMember = "CustTable";
    
                custTransBindingSource.DataSource = custBindingSource;
                custTransBindingSource.DataMember = "CustTable_CustTrans";
    
                custTransOpenBindingSource.DataSource = custTransBindingSource;
                custTransOpenBindingSource.DataMember = "CustTrans_CustTransOpen";
    
            }
        }
    }

    在上面的例子中我们使用的是CustTable Query对象,它有三个Datasource,顶级的CustTable、CustTable下的CustTrans以及CustTrans下的CustTransOpen,返回数据集中包含分别对应三个数据源的数据表,注意数据表的命名方式,是以父数据源的名称通过下划线连接当前数据源的名称得到的。

    需要说明的是在AX Query的Datasource中如果使用了带表继承的基表,在返回的数据集中会同时包含基表和衍生表的数据,这些数据表通过DataRelation对象联系,在基表的数据行对象上调用DataRow.GetChildRows()方法并指定相应的DataRelation参数可以获取相应的衍生表的数据,详细的例子可以参见http://msdn.microsoft.com/EN-US/library/gg843785.aspx

    • 用户自定义查询:在.net中我们可以使用代码创建一个自定义的QueryMetadata对象,再通过QueryMetadata.ExecuteQuery()方法运行这个查询获得数据,这是一个样例:
        QueryServiceClient client = new QueryServiceClient();
    
        DataSet dataSet;
        Paging paging = null;
    
        QueryMetadata query;
        QueryDataSourceMetadata customerDataSource;
    
        query = new QueryMetadata();
    
        // Set the properties of the query.
        query.QueryType = QueryType.Join;
        query.AllowCrossCompany = true;
        query.DataSources = new QueryDataSourceMetadata[1];
    
        // Set the properties of the Customers data source.
        customerDataSource = new QueryDataSourceMetadata();
        customerDataSource.Name = "Customers";
        customerDataSource.Enabled = true;
        customerDataSource.FetchMode = FetchMode.OneToOne;
        customerDataSource.Table = "CustTable";
        // Setting DynamicFieldList property to true returns all fields.
        customerDataSource.DynamicFieldList = true;
        //Add the data source to the query.
        query.DataSources[0] = customerDataSource;
    
        // Execute the query you just created.
        dataSet = client.ExecuteQuery(query, ref paging);

    上面的例子中使用代码创建了一个QueryMetadata对象,添加CustTable表作为数据源Customers,随后调用QueryServiceClient.ExecuteQuery()方法运行这个QueryMetadata对象获取数据。

    在上面我们提到继承表作为查询数据源会通过DataRelation返回衍生表的数据到各自单独的DataTable中,实际上我们可以通过指定queryMetadata.ReturnFlatDataSet属性为true,将基表衍生表的数据返回到一个数据表中:

                using TestQueryService.ServiceReference1;
                using TestQueryService.ServiceReference2;
    
            DataSet dataSet;
                Paging paging = null;
                QueryServiceClient client = new QueryServiceClient();
                AxMetadataServiceClient metadataClient = new AxMetadataServiceClient();
    
    
                // Get the query from the AOT using the metadata service.
                var queryMetadata = metadataClient.GetQueryMetadataByName(new[] { "TestPartiesInWA" })[0];
    
                // Set the query property.
                queryMetadata.ReturnFlatDataSet = true;
    
                // This code is here to convert the queryMetadata object due to namespace conflicts w/mdsr and qsr - remove after M3
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    var queryMetadataQS = new ServiceReference1.QueryMetadata();
    
                    DataContractSerializer mdsSerializer = new DataContractSerializer(typeof(ServiceReference2.QueryMetadata));
                    DataContractSerializer qsSerializer = new DataContractSerializer(typeof(ServiceReference1.QueryMetadata));
                    mdsSerializer.WriteObject(memoryStream, queryMetadata);
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    queryMetadataQS = (ServiceReference1.QueryMetadata)qsSerializer.ReadObject(memoryStream);
    
                    dataSet = client.ExecuteQuery(queryMetadataQS, ref paging);
                }
    
                // Display the flattened dataset in the grid.
                dataGridView1.DataSource = dataSet.Tables["TestPartiesInWA"];

    这个例子中我们使用了MetaData service(工程中中引用的命名空间TestQueryService.ServiceReference2)获取AOT中定义的查询“TestPartiesInWA”,有关的Query查询元数据保存到一个TestQueryService.ServiceReference2.QueryMetadata类型的变量,但是这个变量不能强制转化为Query service的QueryMetadata类型(引入到工程中的命名空间TestQueryService.ServiceReference1),两者在不同的命名空间,所以上面的代码中先把Metadata service的QueryMetadata序列化到一个内存流,再反序列化到Query service的QueryMetadata,给人的感觉奇奇怪怪。

    既然说到使用Metadata service得到AOT中的Query metadata对象后在Query service中使用,再来看看MSDN上的另外一个例子(http://msdn.microsoft.com/EN-US/library/gg844682.aspx),这个例子中使用了带有效时间的表,样例表和表数据用这里的X++代码添加(http://msdn.microsoft.com/EN-US/library/gg861773.aspx),在C#中我们需要指定查询有效时间的起始和终止日期,完整代码如下:

    using System;
    using System.Data;
    using System.IO;
    using System.Runtime.Serialization;
    using TestQueryServiceDateEffect.AxMetadataService;
    using TestQueryServiceDateEffect.QueryServiceReference;
    using ValidTimeStateQueryType = TestQueryServiceDateEffect.AxMetadataService.ValidTimeStateQueryType;
    
    namespace TestQueryServiceDateEffect
    {
        class Program
        {
            static void Main()
            {
                var startDate = new DateTime(2007, 7, 01);
                var endDate = new DateTime(2007, 7, 31);
                Paging paging = null;
                var client = new QueryServiceClient();
                var metadataClient = new AxMetadataServiceClient();
    
    
                // Get the query from the AOT using the metadata service.
                var queryMetadata = metadataClient.GetQueryMetadataByName(new[] { "TestEmployees" })[0];
    
                // Set the date range on the query.
                queryMetadata.ValidTimeStateQueryType =ValidTimeStateQueryType.Range;
                queryMetadata.ValidTimeStateValidFromDateTime = startDate.ToUniversalTime();
                queryMetadata.ValidTimeStateValidToDateTime = endDate.ToUniversalTime();
    
                // Call the query service with the query retrieved 
                // from the metadata service.
                var dataSet = client.ExecuteQuery(MetadataServiceQueryMetadata2QueryServiceQueryMetadata(queryMetadata), ref paging);
    
                var testEmployee = dataSet.Tables["TestEmployee"];
    
                // Loop through the TestEmployee table and display the results.
                if (testEmployee == null || testEmployee.Rows.Count <= 0) return;
                foreach (DataRow row in testEmployee.Rows)
                {
                    Console.WriteLine(row["EmployeeId"] +
                                      "\t" + row["FirstName"] + "\t" +
                                      row["LastName"] + "\t" +
                                      row["ValidFrom"] + "\t" +
                                      row["ValidTo"]);
                }
                Console.ReadLine();
            }
    
            static QueryServiceReference.QueryMetadata MetadataServiceQueryMetadata2QueryServiceQueryMetadata(AxMetadataService.QueryMetadata metadata)
            {
                using (var memoryStream = new MemoryStream())
                {
    
                    var mdsSerializer = new DataContractSerializer(typeof(AxMetadataService.QueryMetadata));
                    var qsSerializer = new DataContractSerializer(typeof(QueryServiceReference.QueryMetadata));
                    mdsSerializer.WriteObject(memoryStream, metadata);
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    var queryMetadataQs = (QueryServiceReference.QueryMetadata)qsSerializer.ReadObject(memoryStream);
    
                    return queryMetadataQs;
                }
            }
        }
    }

    命名空间TestQueryServiceDateEffect.AxMetadataService是我们引入的元数据服务,TestQueryServiceDateEffect.QueryServiceReference则是引入的查询服务,和上面的例子一样,需要在两个命名空间对Query metadata实例进行转换,这里创建了函数MetadataServiceQueryMetadata2QueryServiceQueryMetadata()来做这个动作,另外还需要注意需要使用DateTime.ToUniversalTime()转换为UTC时间传入。

    • 动态查询:使用动态查询首先需要在X++中从AifQueryBuilder类扩展自己的查询类,然后在c#中使用QueryServiceClient.ExecuteDynamicQuery()调用X++的查询类,还是来看具体的例子。
    [DataContractAttribute]
    class CustTransQueryBuilderArgs extends AifQueryBuilderArgs
    {
        CustAccount custAccount;
    }
    
    [DataMemberAttribute]
    public CustAccount parmCustAccount(CustAccount _custAccount = custAccount)
    {
        custAccount = _custAccount;
    
        return custAccount;
    }

    首先在X++中定义了一个继承自AifQueryBuilderArgs的类CustTransQueryBuilderArgs,它带一个参数方法来指定后续查询要使用的客户编号。

    [DataMemberAttribute]
    public CustAccount parmCustAccount(CustAccount _custAccount = custAccount)
    {
        custAccount = _custAccount;
    
        return custAccount;
    }
    
    [DataMemberAttribute]
    public CustAccount parmCustAccount(CustAccount _custAccount = custAccount)
    {
        custAccount = _custAccount;
    
        return custAccount;
    }
    
    [SysEntryPointAttribute()]
    public void initialize()
    {
        QueryBuildDataSource    qbds;
    
        ;
        query = new Query();
        query.addDataSource(tableNum(CustTrans));
        qbds = query.dataSourceTable(tableNum(CustTrans));
        qbds.addRange(fieldNum(CustTrans,AccountNum)).value(args.parmCustAccount());
        queryRun = new QueryRun(query);
    }

    在X++中又定义了一个继承自AifQueryBuilder的类CustTransQueryBuilder,重载方法setArgs()处理传入的查询参数类对象,重载方法initialize()初始化Query和QueryRun对象。在转到c#之前,需要正确编译X++代码并做一次“Incremental CIL”编译,否则在后面引用服务后会找不到参数类CustTransQueryBuilderArgs。和前面一样,在c#工程中添加查询服务的引用,C#程序如下:

    using System;
    using System.Data;
    using TestQueryServiceDynamic.QueryServiceReference;
    
    namespace TestQueryServiceDynamic
    {
        class Program
        {
            static void Main(string[] args)
            {
                var client = new QueryServiceClient();
    
                Paging paging = null;
    
                var custTransArgs = new CustTransQueryBuilderArgs() { parmCustAccount = "3013" };
                var dataSet = client.ExecuteDynamicQuery("CustTransQueryBuilder", custTransArgs, ref paging);
    
                var custTrans = dataSet.Tables[0];
    
                // Loop through the TestEmployee table and display the results.
                if (custTrans == null || custTrans.Rows.Count <= 0) return;
                foreach (DataRow row in custTrans.Rows)
                {
                    Console.WriteLine(row["TransDate"] +
                                      "\t" + row["AccountNum"] + "\t" +
                                      row["AmountMST"] );
                }
                Console.ReadLine();
            }
        }
    }

    不管是哪种查询服务,只有通过验证的用户可以使用查询服务,查询服务使用windows继承验证,所能访问的数据则是依据用户的角色,如果用户没用相应datasource的访问权限,查询服务返回失败错误,如果只是没有表中的某个字段,相应字段将返回空值(DbNull),但是如果这些不能访问的字段出现在数据源连接(Join)、Order by、Group by或者Datasource range中,整个查询服务都将返回失败错误。

  • 相关阅读:
    单例设计模式
    使用JfreeChart生成统计图
    session的生命周期
    json
    struts2 ognl标签使用
    集合小结
    多线程
    内部类和匿名内部类
    模版方法设计模式
    mac中yeoman构建你的项目
  • 原文地址:https://www.cnblogs.com/duanshuiliu/p/2932133.html
Copyright © 2011-2022 走看看