postgresqlnpgsqlpetapoco

Failure to find table when using multiple schemas in PostgreSQL


WPF PostgreSQL 11.1

Npgsql.PostgresException: '42P01: relation "testme" does not exist'

When attempting to use a PostgreSQL database with multiple schemas, I have defined the following connection strings in the App.config. Note that the only difference is in the SearchPath:

 <system.data>
    <DbProviderFactories>
      <add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql Server" type="Npgsql.NpgsqlFactory, Npgsql, Version=4.0.4.0, Culture=neutral" />
    </DbProviderFactories>
  </system.data>
  <connectionStrings>
    <clear />
    <add name="localconnection" providerName="Npgsql" connectionString="Server=127.0.0.1;Port=5432;Database=chaos;User Id=postgres;Password=****;Searchpath=nova" />
    <add name="phoenixconnection" providerName="Npgsql" connectionString="Server=127.0.0.1;Port=5432;Database=chaos;User Id=postgres;Password=****;SearchPath=phoenix;" />
  </connectionStrings>

The Npgsql data provider was installed using NuGet: Runtime Version: v4.0.30319 Version: 4.0.4.0

In PostgreSQL, in the Phoenix schema:

CREATE TABLE phoenix.testme
(
    name text COLLATE pg_catalog."default" NOT NULL
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE phoenix.testme
    OWNER to postgres;

Using PgAdmin, displaying the testme table works without problem:

select * from phoenix.testme;

I have configured the WCF service using the above connection strings. Using PetaPoco, I write the following script:

public string SayHello()
    {
        string msg;
        using (var db = new chaosDB("phoenixconnection"))
        {
            var m = db.ExecuteScalar<string>("select version()");
            msg = string.Format("Hello from {0}", m);

            m = db.ExecuteScalar<string>("select current_schema");
            msg = string.Format("{0} Current Schema is {1}", msg, m);

            var ss = db.ExecuteScalar<string>("show search_path");


            var s = db.Fetch<string>("select * from testme"); <---THIS FAILS!
            msg = string.Format("{0} I Am {1}", msg, m);

        }
        return msg;
    }

All works correctly until the "select * from testme" is executed, when I receive the above error. Note: ss from "show search_path" returns correctly with "phoenix"

WHAT AM I DOING WRONG? How do I get this to work??

Any help is most appreciated?


Solution

  • After much head scratching the answer became self-evident. First I had reset the search_path in the database. This did not help. Then I rebuilt the POCO's with PetaPoco and quickly discovered that not only was the new table, "testme", not created, but nor were any POCO's. So, checking, the Database.tt file in PetaPoco showed it to have the wrong ConnectionStringName. Changing the ConnectionStringName to "phoenixconnection" allowed building the POCO's, but again failed to find the "testme" table.

    Then the mistake became readily apparent, as stated above, both the "phoenixconnection" and the "localconnection" were pointed to the same port. From previous development, I had PostgreSQL v10.1 running on the same port as the newer PostgreSQL v11.1. Apparently, the first PostgreSQL v10.1 was receiving the connection (and not the newer PostgreSQL v11.1).

    Going to services (services.msc) and shutting down v10.1 and running Database.TT now gave the error: System.InvalidOperationException: Sequence contains more than one matching element

    Apparently v10.1 (which I was using for development) only had ONE schema, but v11.1 has multiple schemas. I take the error message to mean that PetaPoco was seeing multiple tables with the same table name--i.e.,it was not distinguishing between schemas.

    So, the problem is now solved.

    1. Fix the ports! The older single-schema PostgreSQL v10.1 is kept on port: 5432. The newer multiple-schema PostgreSQL is kept on port 5433. The v10.1 will be used for the POCO's.
    2. Fix the connection strings in App.config of the WCF so that at run time, the WCF will use the newer v11.1. Once generated, LEAVE THE POCO'S alone and reference them in the WCF file.

    Apparently, PetaPoco, can only work with one schema in generating its POCO's, but at runtime will read the connection strings from the App.Config of the WCF to execute its queries, etc. (So in the App.config where Database.TT resides, point PetaPoco to the "development" Database having only a single schema, but in the WCF environment, point the connection string to the new database with multiple schemas. The SearchPath of the connection string IS respected when running through Npgsql).

    It would be nice if PetaPoco could generate POCO's specific to a schema in a multi-schema environment, but at the moment, I guess it can't :(

    Addendum Note: It turns out that a given instance of PostgreSQL can have multiple DATABASES. So if the connection string for Npgsql is specific to a development database --i.e., a database with only one schema--then during development, PetaPoco works great to create the POCO's. These POCO's can then be directly used in a WCF Service project and uploaded to IIS website. The App.config files of the web site can then be directed to use the run-time database (again in the connection string) to the deployed database. All works well! :)