DBRestToTable Windows Workflow Activity

Эта Activity интресна тем, что переносит данные из базы данных удаленного сервера в локальную базу данных используя технологию Rest. Происходит это так. Аctivity обращаетсся к удаленному серверу и cчитывает там данные одной из таблиц базы данных. Затем, создает на своем сервере, в своей базе данных таблицу для считанных данных, и переписывает туда полученные данные. Кроме того, Activity выполняет все функции описанные ранее в статье ActivityRest. Подключение к локальной базе данных выполняется с использованием Entity, для создания таблицы и вставки данных используются хранимые процедуры, которые вызываются из Linq. Считанные данных последовательно пересылаются сначала на сервер клиента, затем с сервера на машину клиента. Представлен рабочий проект MS Visual Studio 2010 содержащий WCF + WorkFlow + REST + WindowsFormClient, в котором применяется описываемое Activity.
1. Входные данные DBRestToTable.
Входные аргументы этой Activity аналогичны ActivityRest, собраны в классе InputArgument и состоят из двух полей:

public class InputArgument
{
     public string UrlString     { get; set; }
     public string CustomerID    { get; set; }
}
2. Выходные данные DBRestToTable.
Для выходных данных, как и в ActivityRest, не определяется специальный класс. Однако, тип выходных данных, конечно, опреден в protected override EndExecute методе, как IEnumerable<Order>.

protected override IEnumerable<Order> EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
    try
    {
3. Исходный текст DBRestToTable.
Основными действиями в Activity являются подключение к удаленной базе данных, считывание оттуда данных, выполнение хранимой процедуры по созданию таблицы в локальной базе данных, и далее, выполнение в цикле еще одной хранимой процедуры на вставку данных во вновь созданную таблицу. >

/* 25.01.2013.
    Эта Activity интересна тем, что читает данные, используя протокол Rest
    с удаленного сервера, а затем, создает таблицу в базе данных Microsoft SQL
    на своем сервере и записывает в нее считанные данные.
    Базы данных Northwind подключены с использованием Entity, поэтому все операции
    выполняются при помощи Linq.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using WorkFlowRest.ServiceReference1;
using System.Data.Services.Client;
using ClassLibrary;
using System.ComponentModel;

namespace WorkFlowRest
{
    public sealed class DBRestToTable : AsyncCodeActivity<IEnumerable<Order>>
    {
        [RequiredArgument]
        [DefaultValue(null)]
        public InArgument<InputArgument> inputArguments { get; set; }

        NorthwindEntities entityContext             = null;
        DataServiceQuery<Order> entityQuery         = null;

        // Temporary variable for input arguments
        private InputArgument inputObject           = null;
        private string uri                          = null;
        private string customerId                   = null;

        protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
        {
            try
            {
                // Input Object
                inputObject = inputArguments.Get(context);

                //Uri for service
                uri = inputObject.UrlString;
                if (String.IsNullOrEmpty(uri)) throw new ArgumentNullException("Value", "Uri string is Empty");

                // Filter for Data
                customerId = inputObject.CustomerID;
                if (customerId == null) throw new ArgumentNullException("Value", "CustomerID string is null");

                // Set EntityContext
                entityContext = new NorthwindEntities(new Uri(uri));

                // Create entityQuery
                entityQuery = (DataServiceQuery<Order>)
                     from obj in entityContext.Orders
                     where obj.Customer.CustomerID.Contains(customerId)
                     select obj;

                // Set context in Local DataBase
                DataServerDataContext db = new DataServerDataContext();

                // Create table Temp
                 if (db.CreateTable() == -1) throw new ArgumentException("Value", "Error Create table Temp.. ");

                db.SubmitChanges();
                
                // Insert records in table
                foreach (Order item in entityQuery)
                    {
                        if(db.InsertTableTemp(item.OrderID,
                            item.CustomerID,    item.EmployeeID,    item.OrderDate,
                            item.RequiredDate,  item.ShippedDate,   item.ShipVia,       item.Freight,       item.ShipName,
                            item.ShipAddress,   item.ShipCity,      item.ShipRegion,    item.ShipPostalCode, item.ShipCountry) == -1)
                            throw new ArgumentException("Value", "Error insert in table Temp.. ");                       
                            
                            // Debug Activity  
                            //System.Diagnostics.Debug.WriteLine(item.OrderID.ToString());
                    }
                db.SubmitChanges();

                context.UserState = entityQuery;
                return entityQuery.BeginExecute(callback, state);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
                return null;
            }
        }

        protected override IEnumerable<Order> EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
        {
            try
            {
                // Get context.UserState
                entityQuery = context.UserState as DataServiceQuery<Order>;
                // Return entityQuery
                return entityQuery.EndExecute(result);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
                return null;
            }
        }
    }
}
4. Клиент для DBRestToTable
Ниже приведен текст клиента, который формирует и передает URI и фильт данных для DBRestToTable в виде строковых полей класса InputArgument. Затем, клиент принимает данные от сервера, и уже на принятых данных, выполняет еще один Linq запрос. Этот запрос выполняет группировку и сортировку данных по полю CustomerID. Результат второго Linq запроса предназначается для компонента ComboBox в качестве источника данных.

/* 25.01.2013. Клиент для DBRestToTable.
   Формирует и передает на сервер Uri и фильтр для получения данных.
   Отображает полученные данные. Интересен тем, что выполняет Linq запрос на
   полученном ранее результате запроса (первый запрос в DBRestToTable).
   Этот второй Linq запрос используется для
   группировки данных с целью формирования DataSource для ComboBox.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WindowsFormsClient.ServiceReference2;
using ClassLibrary;

namespace WindowsFormsClient
{
    public partial class FormClient : Form
    {
        // Link for Service Client
        ServiceClient client = null;
        // Input Class
        private ClassLibrary.InputArgument input = null;

        public FormClient()
        {
            InitializeComponent();
            // Create Objects and set parameters
            client = new ServiceClient();
            input = new InputArgument();
            input.CustomerID = string.Empty;
            input.UrlString = @"http://services.odata.org/Northwind/Northwind.svc/";
        }

        // Event click button for clean filter
        private void button1_Click(object sender, EventArgs e)
        {
            // Empty Filter comboBox1
            comboBox1.Text = "";
            input.CustomerID = string.Empty;
            //Call Form1_Load
            FormClient_Load(sender, e);
        }

        // Load Data
        private void FormClient_Load(object sender, EventArgs e)
        {
            try
            {
                // Send and Get Data
                var order = client.GetData(input);
                // Too Query
                var groupCustomerID = from row in order
                                      // orderby row.CustomerID ascending
                                      group row by row.CustomerID into grouping
                                      orderby grouping.Key ascending
                                      select grouping.Key;

                foreach (var item in groupCustomerID) comboBox1.Items.Add(item.ToString());

                // Exception is order == null
                if (order == null) { throw new ArgumentNullException("Value", "Order is null"); }

                // Set DataSource
                dataGridView1.DataSource = order;
                label3.Text = order.Count<Order>().ToString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(" Error: " + ex.ToString());
            }
        }

        // Change CustomerID in ComboBox
        private void comboBox1_TextChanged(object sender, EventArgs e)
        {
            try
            {
                input.CustomerID = (string)comboBox1.SelectedItem;
                // Send and Get Data
                var order = client.GetData(input);
                // Exception
                if (order == null) { throw new ArgumentNullException("Value", "Order is null"); }
                // Set DataSource
                dataGridView1.DataSource = order;
                label3.Text = order.Count<Order>().ToString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(" Error: " + ex.ToString());
            }
        }
    }
}
5. SQL текст хранимых процедур.
Ниже приведен текст двух процедур, это CreateTable и InsertTableTemp. Я хочу сослаться на blog Scott Guthrie, откуда взял основу для процедуры InsertTableTemp.

-- Create a table or delete records to a table
ALTER PROCEDURE dbo.CreateTable
AS
BEGIN TRY
    IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Temp'))
    -- if the table exists remove entries
        BEGIN
            DELETE FROM [DBO].[Temp]
           RETURN 1
        END
    -- if the table does not exist create it
    ELSE
        BEGIN
            CREATE TABLE [dbo].[Temp]
            (
                OrderID         int,
                CustomerID      nchar(5),
                EmployeeID      int,
                OrderDate       datetime,
                RequiredDate    datetime,
                ShippedDate     datetime,
                ShipVia         int,
                Freight         money,
                ShipName        nvarchar(40),
                ShipAddress     nvarchar(60),
                ShipCyty        nvarchar(15),
                ShipRegion      nvarchar(15),
                ShipPostalCode  nvarchar(10),
                ShipCountry     nvarchar(15)
            )
        RETURN   2
        END
END TRY
-- if Error return -1
BEGIN    CATCH
     RETURN -1
END      CATCH

-- INSERT RECORD IN TEMP
ALTER PROCEDURE dbo.InsertTableTemp    
    (
        @OrderID        int,
        @CustomerID     nchar(5),
        @EmployeeID     int,
        @OrderDate      datetime,
        @RequiredDate   datetime,
        @ShippedDate    datetime,
        @ShipVia        int,
        @Freight        money,
        @ShipName       nvarchar(40),
        @ShipAddress    nvarchar(60),
        @ShipCyty       nvarchar(15),
        @ShipRegion     nvarchar(15),
        @ShipPostalCode nvarchar(10),
        @ShipCountry    nvarchar(15)
    )

    AS
    BEGIN TRY
        INSERT INTO [dbo].[Temp]
            ([OrderID],[CustomerID],[EmployeeID],[OrderDate],[RequiredDate],[ShippedDate],[ShipVia],[Freight],
            [ShipName],[ShipAddress],[ShipCyty],[ShipRegion],[ShipPostalCode],[ShipCountry])
        VALUES
            (@orderID, @CustomerID,@EmployeeID,@OrderDate,@RequiredDate,@ShippedDate,@ShipVia, @Freight,@ShipName,        
            @ShipAddress, @ShipCyty,@ShipRegion, @ShipPostalCode,@ShipCountry)    

        SET @OrderID = CAST (SCOPE_IDENTITY() AS INT)
        RETURN 1
    END TRY
    BEGIN CATCH
        RETURN - 1
    END   CATCH

Visual Studio 2010 проект содержащий: Activity, Workflow, Windows Form клиент можно загрузить.
Евгений Вересов.
25.01.2013 года.