Реализация транзакций LINQ-to-SQL через WCF - PullRequest
1 голос
/ 16 апреля 2009

У меня есть служба WCF, которая используется для добавления тендеров в базу данных, то есть MS SQL Server 2005. WCF использует LINQ-to-SQL.

В каждом тендере может быть много документов и много предметов. Клиенты могут добавить один объект за сервисный вызов. То есть сделать что-то вроде этого:

TendersServiceClient service = new TenderServiceClient();
service.BeginTransaction();

// Adding a new tender
service.AddTender(TenderDTO tenderInfo);

// Adding tender's documents
foreach (DocumentDTO documentInfo in documents)
   service.AddTenderDocument(tenderInfo.TenderID, documentInfo);

// Adding tender's items
foreach (ItemDTO itemInfo in items)
   service.AddTenderItem(tenderInfo.TenderID, itemInfo);

service.CommitTransaction();

Обратите внимание на BeginTransaction () и CommitTransaction (). То есть вся описанная выше процедура должна либо полностью завершиться, либо полностью откатиться. Например, если один из предметов не может быть вставлен, тогда весь тендер не должен существовать ...

Так что вопрос в том, как мне реализовать этот вид транзакции. Проблема в том, что WCF не имеет статуса, конечно. Таким образом, новый DataContext создается для каждого вызова службы. Если я вместо этого использую статический DataContext, то я смогу использовать его встроенные возможности транзакций, но тогда как я могу обращаться с другими клиентами, которые могут попытаться добавить еще один тендер в одно и то же время (они должны быть, конечно, вне этой транзакции)?

Так что, пожалуйста, помогите мне с каким-то шаблоном дизайна для достижения этой цели. Я свободен изменять код как службы, так и клиента, поэтому не стесняйтесь с вашими предложениями =)

Ответы [ 2 ]

2 голосов
/ 26 сентября 2009

Контролируете ли вы интерфейс сервиса?

Если это так, то, безусловно, элегантное решение для службы - принять совокупный объект Tender в одном методе, а не использовать методы chatty, которые есть у вас сейчас. В этом случае Тендер будет иметь в качестве подколлекций Предметы и Документы, и код доступа к данным сможет гораздо проще обрабатывать все обновления в одной транзакции.

Если я не понимаю, это похоже на сценарий Order / OrderDetails, где применяется та же логика.

1 голос
/ 16 апреля 2009

Во-первых, вам придется использовать транзакционные сервисные вызовы здесь - и поскольку у вас есть «инициализирующий» вызов, несколько промежуточных вызовов, а затем, возможно, один для завершения всех вызовов, я бы порекомендовал вам взглянуть на атрибуты «IsInitiating» и «IsTerminating» в OperationContract для методов - это позволит вам указать один метод для начала сеанса и один для его завершения.

Затем убедитесь, что вы сконфигурировали свою службу как транзакционную, указав атрибут «TransactionFlow» либо для службы, либо для всех операций - в зависимости от того, что вы предпочитаете.

В вашем клиентском коде вам придется использовать System.Transactions для создания TransactionScope, который будет упаковывать ваши сервисные вызовы. Это легкий или полностью двухфазный координатор распределенных транзакций - в зависимости от того, что ваши звонки делают подробно.

Что-то в этом роде:

1) Отметить привязку как транзакционную:

<bindings>
  <wsHttpBinding>
    <binding name="TransactionalWsHttp" transactionFlow="true" />
  </wsHttpBinding>
</bindings>

2) Договор на обслуживание:

[ServiceContract]
public interface ITenderService
{
  // method to start your submission process
  [OperationContract(IsInitiating=true, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void StartTenderProcess();

  // all your other methods "in between"
  [OperationContract(IsInitiating=false, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void AddTender()

  [OperationContract(IsInitiating=false, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void AddTenderDocument()

  [OperationContract(IsInitiating=false, IsTerminating=false)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void AddTenderItem()

  ...

  // method to end your submission process
  [OperationContract(IsInitiating=false, IsTerminating=true)]
  [TransactionFlow(TransactionFlowOption.Mandatory]
  public void FinishTenderProcess();
}

3) В коде вашего клиента:

using (TransactionScope ts = new TransactionScope())
{
   serviceClient.StartTenderProcess();

   ..... 

   serviceClient.FinishTenderProcess();

   ts.Complete();   // Transaction Commit 
}

Помогает ли это вам на время начать ?? ?? 1018 *

Марк

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...