Search code examples
databaseormpetapoco

PetaPoco GetInstance() always return new instance?


Just have a question regarding PetaPoco generated Database.cs code from version 4.0.3. See below code snippet:

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 />

Looking at the GetInstance() function, why is it that the return new postgresqlDB() is never assigned to the private variable _instance?

Doesn't this mean every call to GetInstance() will always create a new instance because if (_instance != null) return _instance; will never be true?

Thanks all for the help.


Solution

  • I ran into this behavior today as well with PetaPoco. (Hat's off to the creator(s) since it is generally a pleasure to use!). In a related situation, I wanted to pull a copy of the most recent sql passed through PetaPoco in order to review it with code like:

    Console.WriteLine(RepositoryTableClass.repo.LastCommand);
    

    In my case it was always empty for exactly the reason as OP suggests. The threadstatic marker is orthogonal to the original question. The only place in code where the _instance variable is set is for the duration of a transaction. As a result each instance of the repository is used and abandoned by default. (This may be to avoid problems with re-using the single connection for multiple overlapping queries\results?)

    In any case the factory pattern is available and can be used to force reliance on a single repo instance if that is what you desire. Try a super simple factory class like:

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

    Set the factory before you begin using any repository objects like so:

    postgresqlDB.Factory = new RepoFactory(); 
    

    That enabled me to use repository objects against a single repository instance as verified by having a populated value for the last command after each usage...

    RepositoryTableClass.repo.LastCommand