简体   繁体   中英

Wrong query generated by PostgreSQL provider to Entity Framework for Contains and Concat

I'm using EF to connect to PostgreSQL. EF is in 5.0 version, Npgsql in 2.0.14.3.

The query that I want to run is:

var list = new List<string> { "test" };

var res = from t in db.Test
    where !list.Contains(string.Concat(t.test1, "_", t.test2))
    select t;
res.ToList();

The query that is generated is something like:

SELECT "Extent1"."id" AS "id","Extent1"."test1" AS "test1","Extent1"."test2" AS "test2" FROM "public"."test" AS "Extent1" WHERE 'test'!="Extent1"."test1" || '_' || "Extent1"."test2"

And when I run it I get an error: argument of WHERE must be type boolean, not type text .

However, when I change != to = it works. It works also when I add a parantheses around concatenated strings in Postgres but I cannot change the query that EF generates.

The workaround is that I add the second (dummy) element to the list because then EF generates a bit different query but it isn't an elegant solution…

Is it a bug in pgSQL? Or maybe in EF provider? Can you suggest a better solution to that problem?

MORE INFORMATION

The table script:

CREATE TABLE test
(
  test1 character varying(255),
  test2 character varying(255),
  id integer NOT NULL,
  CONSTRAINT "PK" PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);

The class for the table:

[Table("test", Schema = "public")]
public class Test
{
    [Key]
    public int id { get; set; }

    public string test1 { get; set; }

    public string test2 { get; set; }
}

App.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  </entityFramework>
  <connectionStrings>
    <add name="local" connectionString="Server=localhost;Port=5432;Database=test;User Id=user;Password=password;" providerName="Npgsql" />
  </connectionStrings>
  <system.data>
    <DbProviderFactories>
      <add name="Npgsql Data Provider" invariant="Npgsql" description="Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql" />
    </DbProviderFactories>
  </system.data>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
  </startup>
</configuration>

Yes, that's a bug in the EF provider Npgsql.

According to http://www.postgresql.org/docs/9.3/static/sql-syntax-lexical.html#SQL-PRECEDENCE-TABLE , != and || are among (any other) , which means they have the same precedence. They are also left associative, so that query will be parsed as

SELECT ... FROM "public"."test" AS "Extent1"
WHERE ((('test'!="Extent1"."test1") || '_') || "Extent1"."test2")

which is wrong. The correct parsing would be

SELECT ... FROM "public"."test" AS "Extent1"
WHERE ('test'!=(("Extent1"."test1" || '_') || "Extent1"."test2"))

= have lower precedence than != so that works.

A fix for this is included in the pull request at https://github.com/npgsql/Npgsql/pull/256 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM