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 года.
|