Метод знает слишком много о методах, которые он называет

У меня есть метод, что я хочу быть "транзакционным" в абстрактном смысле. Это называет два метода, которые, оказывается, делают материал с базой данных, но этот метод не знает это.

public void DoOperation()
{
    using (var tx = new TransactionScope())
    {
        Method1();
        Method2();

        tc.Complete();
    }
}

public void Method1()
{
    using (var connection = new DbConnectionScope())
    {
        // Write some data here
    }
}

public void Method2()
{
    using (var connection = new DbConnectionScope())
    {
        // Update some data here
    }
}

Поскольку в реальном выражении TransactionScope средства, что транзакция базы данных будет использоваться, у нас есть проблема, где это могло способствоваться Распределенной транзакции, если мы получаем два различных соединения от пула.

Я мог зафиксировать это путем обертывания DoOperation() метод в ConnectionScope:

public void DoOperation()
{
    using (var tx = new TransactionScope())
    using (var connection = new DbConnectionScope())
    {
        Method1();
        Method2();

        tc.Complete();
    }
}

Я сделал DbConnectionScope самостоятельно для просто такой цели, так, чтобы я не передавал объекты соединения подметодам (это - более изобретенный пример, чем моя реальная проблема). Я получил идею из этой статьи: http://msdn.microsoft.com/en-us/magazine/cc300805.aspx

Однако мне не нравится это обходное решение, как это означает DoOperation теперь имеет знание, что методы, которые это называет, могут использовать соединение (и возможно другое соединение каждый). Как я мог осуществить рефакторинг это для решения вопроса?

Одна идея, о которой я думаю, создает более общее OperationScope, так, чтобы при объединениях с пользовательским образом жизни замка Windsor я записал, будет означать любой компонент, который требуют от контейнера с OperationScopeLifetyle будет всегда получать тот же экземпляр того компонента. Это действительно решает проблему потому что OperationScope более неоднозначно, чем DbConnectionScope.

7
задан Neil Barnwell 21 January 2010 в 12:38
поделиться

2 ответа

Я вижу противоречивые требования здесь.

С одной стороны, вы не хотите Dooperation , чтобы иметь какое-либо осознание того факта, что соединение базы данных используется для его подпрограммы.

С другой стороны, это четко осознает этот факт, потому что он использует A Skresscope .

Я могу понять, что вы получаете, когда вы говорите, что хотите, чтобы он был транзакционным в абстрактном смысле , но мой взять на себя это то, что он практически невозможно (нет, царапает это полностью невозможно) описать транзакцию в таких абстрактных терминах. Давайте просто скажем, у вас есть такой класс:

class ConvolutedBusinessLogic
{
    public void Splork(MyWidget widget)
    {
        if (widget.Validate())
        {
            widgetRepository.Save(widget);
            widget.LastSaved = DateTime.Now;
            OnSaved(new WidgetSavedEventArgs(widget));
        }
        else
        {
            Log.Error("Could not save MyWidget due to a validation error.");
            SendEmailAlert(new WidgetValidationAlert(widget));
        }
    }
}

Этот класс делает по крайней мере две вещи, которые, вероятно, не могут быть откатываться от спины (устанавливая свойство класса и выполнение обработчика событий, что может например, Cascade-Update Управление в форме) и, по крайней мере, еще два веща, что определенно не может быть откатано (присоединяется к файлу журнала где-то и отправка адресата электронной почты).

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

То, как я его вижу, у вас есть несколько разных вариантов:

  1. сделать явную то, что Method1 и Method2 требуют соединения, имея их принимать параметр подключения, или путем рефакторизации их в класс, который принимает зависимость соединения (конструктор или свойство). Таким образом, соединение становится частью контракта , поэтому Метод1 больше не знает слишком много - он точно знает, что он должен знать в соответствии с дизайном.

  2. Примите, что ваша метод имеет осознание метода и метода2 . На самом деле, Нет ничего плохого в этом! Это правда, что вы не хотите полагаться на детали реализации некоторых будущих звонков, но прямых зависимостей в абстракции, как правило, считаются нормальными; Это Регистрация зависимости зависимостей, которые вы должны быть обеспокоены, вроде бы, когда какой-то класс глубоко в модели домена пытается обновить управление пользовательским интерфейсом, о котором нет бизнеса, зная в первую очередь.

  3. Используйте более прочную единицу работы Узор (также: здесь ). Это становится все более популярным, и он, по и BARE, направление Microsoft вошел с LINQ к SQL и EF ( DataContext / ObjectContext в основном реализации UOW). Эти рукава в колодете с Di Framework и, по существу, снимают вас о необходимости беспокоиться о том, когда транзакции начинаются и заканчиваются, и как должен произойти доступ к данным (термин - это «нежеливание настойчивости»). Это, вероятно, потребует значительных перепроектов вашего дизайна, но фунт за фунт, он будет самым простым, чтобы поддерживать долгосрочные.

Надеюсь, один из тех помогает вам.

2
ответ дан 7 December 2019 в 18:43
поделиться

Я предпочитаю избегать скриптов в середине своей страницы и должен был использовать их (все чаще), чтобы избежать последовательностей при использовании в коде JavaScript. Я хотел Язык выражения (EL) способ избежать последовательности. Я создал очень маленький пользовательский tallib, который я использую только для этой цели:

Utilities.java:

package com.mycom.taglibs;

import org.apache.commons.lang.StringEscapeUtils;

public class Utilities {
    public static String escapeJS(String value) {
        return StringEscapeUtils.escapeJavaScript(value);
    }
}

mytaglib.tld:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">

  <description>My Tag Library</description>
  <display-name>Tag Utils</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>myt</short-name>

  <function>
    <description>
        JavaScript Escape function
    </description>
    <name>escapeJS</name>
    <function-class>com.mycom.taglibs.Utilities</function-class>
    <function-signature>java.lang.String escapeJS(java.lang.String)</function-signature>
  </function>
</taglib>

И, на странице JSP:

<%@ taglib prefix="myt" uri="/WEB-INF/mytaglib.tld" %>
The escaped string is: ${myt:escapeJS(variableHoldingTheString)}
-121--1299625-

Следующие сценарии написаны в sybase sql. Возможно, потребуется выполнить незначительные изменения в соответствии с сервером БД.

1 проблемы.

create table #connections (
    my_user  varchar(10)  not null  ,
    knows varchar(10)  not null  ,
        CONSTRAINT connection_pk PRIMARY KEY CLUSTERED ( my_user, knows)   
) 

create table #traversed (id varchar(10) primary key)

insert into #connections VALUES ('UserA','UserB')
insert into #connections VALUES ('UserB','UserA')
insert into #connections VALUES ('UserB','UserC')
insert into #connections VALUES ('UserC','UserB')
insert into #connections VALUES ('UserC','UserD')
insert into #connections VALUES ('UserD','UserC')
insert into #connections VALUES ('UserD','UserF')
insert into #connections VALUES ('UserF','UserD')

DECLARE @str_sql   varchar(200)               
DECLARE @str_order varchar(60)

declare @start varchar(10)
set @start = ('UserD')
declare @end varchar(10)
set @end = ('UserA')

if (@start >= @end)
    set @str_order = " order by id desc"
else
    set @str_order = " order by id asc"


INSERT INTO #traversed VALUES (@start)

WHILE (select count(*) from #traversed where id = @end) = 0    
BEGIN     
  INSERT INTO #traversed (id)    
  SELECT DISTINCT knows  
  FROM #connections e JOIN #traversed p ON p.id = e.my_user  
  WHERE e.knows NOT IN (SELECT id FROM #traversed)     
  AND e.knows between (select case when @start < @end then @start else @end end)  
      and (select case when @start < @end then @end  else @start end) 
END

set @str_sql = "SELECT #traversed.id FROM #traversed" + @str_order 
exec (@str_sql)

Проблема 2.

create table #connections (
    my_user  varchar(10)  not null  ,
    knows varchar(10)  not null  ,
        CONSTRAINT connection_pk PRIMARY KEY CLUSTERED ( my_user, knows)   
) 

create table #traversed (id varchar(10) primary key)

insert into #connections VALUES ('UserA','UserB')
insert into #connections VALUES ('UserB','UserA')
insert into #connections VALUES ('UserB','UserC')
insert into #connections VALUES ('UserC','UserB')
insert into #connections VALUES ('UserC','UserD')
insert into #connections VALUES ('UserD','UserC')
insert into #connections VALUES ('UserD','UserF')
insert into #connections VALUES ('UserF','UserD')

declare @start varchar(10)
set @start = ('UserB')

declare @higher_counter int
declare @lower_counter int

set @higher_counter = 0
set @lower_counter = 0

INSERT INTO #traversed VALUES (@start)

WHILE (@higher_counter < 3)
BEGIN     
  INSERT INTO #traversed (id)    
  SELECT DISTINCT knows  
  FROM #connections e JOIN #traversed p ON p.id = e.my_user  
  WHERE e.knows NOT IN (SELECT id FROM #traversed)     
  AND e.knows > @start 

  set @higher_counter = @higher_counter +1
END  

WHILE (@lower_counter < 3)
BEGIN     
  INSERT INTO #traversed (id)    
  SELECT DISTINCT knows  
  FROM #connections e JOIN #traversed p ON p.id = e.my_user  
  WHERE e.knows NOT IN (SELECT id FROM #traversed)     
  AND e.knows < @start 

  set @lower_counter = @lower_counter +1
END   

SELECT #traversed.id FROM #traversed
-121--1645612-

Можно ли передать/зачислить транзакцию в БД и полностью удалить ее из кода?

0
ответ дан 7 December 2019 в 18:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: