структура сущности + репозиторий + вопрос о единице или работе

Я подумываю о запуске нового проекта с использованием EF 4 и просматривая некоторые статьи, я нашел статью о EF с шаблоном репозитория и единицей работы (http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-4-0.aspx)

Глядя на эту статью, он использует ObjectContext как UnitOfWork и передает его в репозиторий.

Мой вопрос: что, если у меня есть 2 ObjectContext, что означает, что у меня будет 2 единицы работы, но на самом деле я хочу, чтобы все операции, выполняемые с этими 2 контекстами, были одной единицей работы, возможен ли этот сценарий? Я не хочу вызывать save для каждого контекста, я бы хотел, чтобы это было транзакционным .... без использования transactioncope ...

Например, у меня есть контекст, который управляет журналом операций, и другой контекст, который управляет заказами. Допустим, на моем бизнес-уровне у меня есть метод AddOrder (). AddOrder () будет использовать контекст заказа для создания нового заказа, но он также будет использовать контекст журнала операций для создания новой записи журнала операций. Поскольку это 2 контекста, мне нужно будет вызвать save для обоих контекстов, чтобы зафиксировать .... возможно, единственный вариант - иметь только один единственный контекст ....

РЕДАКТИРОВАТЬ: я имел в виду 2 контекста разных типов, например: OperationalLogContext и OrderContext.


person pdiddy    schedule 15.09.2010    source источник


Ответы (1)


Ага - я считаю, что это возможно.

Кикер - это то, как обращаться с вашими репозиториями.

Например, каждый репозиторий должен принимать контекст ... поэтому просто создайте один контекст и передайте его каждому репозиторию.

(код, пожалуйста!) Рад, что ты спросил :)

public interface IOrderRepository
{
    IQueryable<Order> FindAll();
}

public interface IOperationLogRepository
{
    IQueryable<OperationLog> FindAll();
}

public interface IUnitOfWork
{
    void Commit();
}

.

public class SqlServerContext : ObjectContext, IUnitOfWork
{
    public void SqlServerContext(string connectionString) 
        : base(connectionString)
    {
    }

    public void Commit()
    {
        this.SaveChanges();
    }

    // Your other POCO's and stuff here ..etc..
}

.

public class OrderRepostiory : IOrderRepository
{
    private readonly SqlServerContext _sqlServerContext;
    public void OrderRepostiory(SqlServerContext sqlServerContext)
    {
        _sqlServerContext = sqlServerContext;
    }

    public IQueryable<Order> FindAll()
    {
        _sqlServerContext.Orders;
    }
}

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

public class SqlServerRegistry : Registry
{
    public SqlServerRegistry(string connectionString)
    {
        For<SqlServerContext>()
            .HybridHttpOrThreadLocalScoped()
            .Use<SqlServerContext>()
            .Ctor<string>("connectionString")
                .Is(connectionString);

        For<IOrderRepository>().Use<OrderRepository>();
        For<IOperationLogRepository>().Use<OperationLogRepository>();
    }
}

и поскольку SqlServerContext определен как HttpOrThreadLocal, он будет создан ОДИН РАЗ и повторно использован в нескольких репозиториях.

Не знаете или не понимаете DI / IoC?

тогда это тоже сработает ....

private SqlServerContext _sqlServerContext;
private IOrderRepository _orderRepository;
private IOperationLogRepository _operationLogRepository;

[TestInitialize]
public void TestInitialise()
{
    _sqlServerContext = new SqlServerContext(
             ConfigurationManager.AppSettings["connectionString"]);
    _orderRepository = new OrderRepository(_sqlServerContext);
    _operationLogRepository= new OperationLogRepository(_sqlServerContext);
}

[TestMethod]
public void SomeTest()
{
    // Arrange.
    const int count = 10;

    // Act.
    var orders = _orderRepository.FindAll().Take(10).ToArray();

    // Assert.
    Assert.IsNotNull(orders);
    CollectionAssert.AllItemsAreNotNull(orders);
    Assert.AreEqual(count, orders.Length);
}

еще раз, это весь непроверенный код, который я только что набрал, когда думал над ответом на этот вопрос.

HTH.

person Pure.Krome    schedule 15.09.2010
comment
Спасибо, это очень помогает. Итак, единственный способ - действительно иметь только один контекст ... и если у меня есть 2 контекста, у меня не будет другого выбора, кроме как прибегнуть к некоторому механизму транзакции, это правильно? - person pdiddy; 15.09.2010
comment
Неа. Вы можете иметь столько, сколько хотите. обратите внимание, как в случае внедрения зависимости я сказал HttpScopeOrThreadScope? Вы можете изменить его на одноэлементный (плохая идея) или значение по умолчанию, которое должно new создавать новый экземпляр каждый раз, когда запрашивается объект. Так что решать вам :) Если вы делаете второй способ (который я сделал на тестовом примере), то да ... вам придется вручную обновлять каждый контекст, один за другим. например var context1 = new SSC(..); var context 2 = new SSC(...); _or = new OR(context1); _olr = new OLR(context2); и т. д. - person Pure.Krome; 15.09.2010
comment
Пришлось обновить свой ответ - в нем была серьезная ошибка. Я заменил любую ссылку на new EntityConnection(connectionString) на простой connectionString, потому что соединение не удалялось, если контекст не создавал EntityConection (вместо того, чтобы передавать в него). Приветствую Айенде Рахиен (из Hibernating Rhino's) за исправление. - person Pure.Krome; 15.09.2010
comment
Я имел в виду например 2 контекста разных типов: OperationalLogContext и OrderContext. Я думаю, вы имели в виду несколько контекстов одного и того же типа (SqlServerContext) и что модель operatingLog и ordermodel находятся внутри sqlservercontext. Я имел в виду, что Operatinallogcontext будет управлять операционным, а ordercontext управляет моделью заказа. Извините за путаницу. - person pdiddy; 15.09.2010
comment
Ах да ... - тогда я неправильно понял ваш вопрос :( Я подумал, что вы хотите избежать использования двух контекстов, потому что у вас 2 репозитория. Из интереса, почему вы хотите 2x контекстов? Во-вторых - вот связанный вопрос, только что заданный кем-то другим: stackoverflow.com/questions / 3717997 / - person Pure.Krome; 15.09.2010
comment
Но спасибо, ваш ответ помог мне больше узнать о шаблоне репозитория и модуле работы. Речь шла скорее о его структурировании, но теперь, возможно, это все-таки хорошая идея. - person pdiddy; 15.09.2010