PetaPoco GetInstance() всегда возвращает новый экземпляр?

У меня просто есть вопрос относительно сгенерированного PetaPoco кода Database.cs из версии 4.0.3. См. ниже фрагмент кода:

public partial class postgresqlDB : Database
{
    public postgresqlDB() 
        : base("postgresql")
    {
        CommonConstruct();
    }

    public postgresqlDB(string connectionStringName) 
        : base(connectionStringName)
    {
        CommonConstruct();
    }

    partial void CommonConstruct();

    public interface IFactory
    {
        postgresqlDB GetInstance();
    }

    public static IFactory Factory { get; set; }
    public static postgresqlDB GetInstance()
    {
        if (_instance!=null)
            return _instance;

        if (Factory!=null)
            return Factory.GetInstance();
        else
            return new postgresqlDB();
    }

    [ThreadStatic] static postgresqlDB _instance;

    public override void OnBeginTransaction()
    {
        if (_instance==null)
            _instance=this;
    }

    public override void OnEndTransaction()
    {
        if (_instance==this)
            _instance=null;
    }
.....
..... <snip />

Глядя на функцию GetInstance(), почему return new postgresqlDB() никогда не присваивается частной переменной _instance?

Разве это не означает, что каждый вызов GetInstance() всегда будет создавать новый экземпляр, потому что if (_instance != null) return _instance; никогда не будет истинным?

Спасибо всем за помощь.


person Spongebob    schedule 24.07.2012    source источник
comment
У вас есть код для CommonConstruct()? Я бы предположил, что это может быть установка переменной там   -  person John D    schedule 24.07.2012
comment
Это сгенерированный код PetaPoco с помощью шаблонов TT. Из коробки это все, что есть. Мне просто любопытно, почему в сгенерированном коде нет присвоения _instance.   -  person Spongebob    schedule 24.07.2012


Ответы (2)


Я столкнулся с таким поведением сегодня и с PetaPoco. (Снимаю шляпу перед создателем(ями), так как пользоваться им, как правило, одно удовольствие!). В похожей ситуации я хотел получить копию самого последнего sql, прошедшего через PetaPoco, чтобы просмотреть его с помощью кода вроде:

Console.WriteLine(RepositoryTableClass.repo.LastCommand);

В моем случае он всегда был пуст именно по той причине, что предлагает ОП. Маркер threadstatic ортогонален исходному вопросу. Единственное место в коде, где установлена ​​переменная _instance, — это время транзакции. В результате каждый экземпляр репозитория используется и забрасывается по умолчанию. (Это может быть сделано для того, чтобы избежать проблем с повторным использованием одного соединения для нескольких перекрывающихся запросов\результатов?)

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

private class RepoFactory : postgresqlDB.IFactory
{
        private static postgresqlDB repo = postgresqlDB.GetInstance();

        public postgresqlDB GetInstance()
        {
            return repo;
        }
}

Установите фабрику, прежде чем вы начнете использовать какие-либо объекты репозитория, например:

postgresqlDB.Factory = new RepoFactory(); 

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

RepositoryTableClass.repo.LastCommand
person user2916083    schedule 05.02.2014
comment
Ваш подход также похож на наш. - person Spongebob; 27.05.2014

Вы приписали поле _instance с помощью ThreadStatic. Это означает, что в поле для каждого потока используется другое значение для доступа к нему. Если GetInstance всегда вызывается с новым потоком, он всегда будет иметь новое значение (другими словами, каждый раз вызывать конструктор)

person Peter Ritchie    schedule 24.07.2012
comment
Я понимаю. Что, если по какой-то причине GetInstance() вызывается несколько раз в одном и том же потоке? Тогда в этом сценарии при каждом вызове всегда будет возвращаться новый экземпляр postgresqlDB? - person Spongebob; 24.07.2012
comment
Из того же потока он вызывает конструктор в первый раз, а затем возвращает то же значение в последующие разы. Я бы рекомендовал использовать Lazy‹T› вместо использования поля экземпляра... - person Peter Ritchie; 24.07.2012
comment
Если мы посмотрим на реализацию GetInstance() в операторе else return new postgresqlDB();, похоже, что он никогда не устанавливает локальную переменную _instance в созданный экземпляр. Так что, даже если в том же потоке, он также не возвращает новые экземпляры postgresqlDB? - person Spongebob; 24.07.2012