Как я могу проверить, находится ли текущая операция в области объекта? - PullRequest
1 голос
/ 25 февраля 2009

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

Мой сценарий

У меня есть класс (EntityBase), на котором построены все объекты базы данных, и есть такие методы, как AddToDatabase, UpdateInDatabase, DeleteFromDatabase.

Я хочу создать класс BulkLoader, который будет массово обрабатывать вставки. Тогда у него будет завершенный метод, такой как класс TransactionScope, который будет точкой загрузки данных в базу данных.

Для этого потребуется изменить класс EntityBase, чтобы он вел себя по-разному, если он создается в рамках класса BulkLoader и взаимодействует с этим классом.

Пример кода:

using (BulkLoader bulk = new BulkLoader(connection, transaction))
{
    foreach (IToDatabase assignment in assignmentsCollection)
    {
        assignment.WriteToDataBase(connection, transaction);
    }

    bulk.Complete();
}

class ClientAssignment : IToDatabase
{
     public int WriteToDataBase(IDbConnection connection, 
         IDbTransaction transaction)
     {
          foreach (EntityBase account in accountsCollection)
          {
                account.AddToDataBase(connection, transaction);
          }

          foreach (EntityBase person in personsCollection)
          {
                person.AddToDataBase(connection, transaction);
          }
     }
}

class EntityBase
{
    public virtual int AddToDatabase(IDbConnection connection, 
        IDbTransaction transaction)
    {
        // question relates to this bit
        if (inBulkLoaderClass)
        {
            // interact with bulk loader
        }
        else 
        {
            // do existing code
        }
    }
}

Ответы [ 3 ]

4 голосов
/ 25 февраля 2009

Вы можете использовать ThreadStaticAttribute :

public class BulkLoader : IDisposable
{
    [ThreadStatic]
    private static BulkLoader currentBulkLoader;

    public BulkLoader()
    {
        if (InBulkLoader)
        {
            throw new InvalidOperationException();
        }
        currentBulkLoader = this;
    }

    public void Dispose()
    {
        currentBulkLoader = null;
    }

    public static bool InBulkLoader
    {
         get { return currentBulkLoader != null; }
    }

    public static BulkLoader CurrentBulkLoader
    {
         get { return currentBulkLoader; }
    }
}

Обычно я не увлекаюсь статикой потоков, но, думаю, в этом случае все нормально. Проверка в конструкторе гарантирует, что вы никогда не будете в «вложенном» массовом загрузчике. Если вы хотите, чтобы могли их вкладывать, используйте вместо этого счетчик (приращение в конструкторе, уменьшение в вызове Dispose).

1 голос
/ 25 февраля 2009

Ну, есть некоторые вещи, которые вы можете делать с окружающими объектами (в частности, со статическими полями потока), но это не очень красиво. Я бы сказал, что если логика другая, это должен быть отдельный метод. Кроме того, обратите внимание, что одна точка зрения состоит в том, что объекты сущности в любом случае не должны взаимодействовать с базой данных - их работа состоит в том, чтобы представлять состояние объекта; Это задача класса репозитория (или подобного) - беспокоиться о постоянстве. Тогда у вашего хранилища будет две стратегии, чтобы справиться с вещами. Возможно, существует интерфейс IBulkRepository, который может (возможно) реализовать репо и т. Д.

0 голосов
/ 25 февраля 2009

Я согласен с Марком здесь. Мы тоже придерживаемся почти того же подхода, который показал Марк. Я думаю, что это стандартный и оптимальный способ решения такой проблемы. Хотя я не очень знаком с бизнесом потоковой статики, поэтому не могу предложить больше в этом.

...