Пользовательское приведение postgresql для соответствия различным типам дел - PullRequest
0 голосов
/ 18 октября 2018

Некоторые фоны, которые я использую:

  • Платформа сущностей 6.1
  • Devart.Data.PostgreSql 7.11.1229
  • Devart.Data 5.0.2021
  • Postgresql 9.2

Из-за некоторого абстрактного ОО-моделирования EntityFramework вынужден выполнять некоторые объединения для разных таблиц, некоторые из которых могут содержать столбец JSONB, другие - нет.По сути это выглядит следующим образом:

select
    c1,
    c2,    
    case when 
        c4 = true then c3 
        else cast(null as varchar) 
    end as c3,
    c4
from (
    select
        id as c1,
        name as c2,
        attributes as c3,
        true as c4
    from
        myjsonbtable
    union all
    select
        id as c1,
        name as c2,
        null as c3,
        false as c4
    from
        mynormaltable
) as union_all

Когда вы выполняете этот запрос, Postgresql выдаст следующую ошибку:

ERROR:  CASE types character varying and jsonb cannot be matched

это происходит из следующей строки кода:

case when c4 = true then c3 else cast(null as varchar) end as c3

, который мы могли бы исправить следующим образом:

case when c4 = true then c3 else cast(null as jsonb) end as c3

При условии, что мы ударяем EF палкой.Проще было бы, если бы мы могли сказать Postgresql, как приводить эти типы:

что-то вроде:

create cast (varchar as jsonb) with function to_jsonb(anyelement) as implicit;

Но мне интересно, сможет ли CASE действительно выполнять неявный CAST изсимвол меняется от jsonb для соответствия типам?

Или, может быть, кто-то другой, отличная идея, либо с точки зрения Postgresql, либо с EntityFramework.

Редактировать: см. пример представленного кода

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DevartExample
{

    [Table("BaseClass")]
    public class BaseClass
    {
        [Index]
        public int Id { get; set; }
    }

    [Table("ClassWithJsonb")]
    public class ClassWithJsonB : BaseClass
    {
        [Column(TypeName = "jsonb")]
        public string Json { get; set; }
    }

    [Table("ClassWithoutJsonb")]
    public class ClassWithoutJsonB : BaseClass
    {
        public int MyProperty { get; set; }
    }

    public class DevartDbProvider : DbContext
    {
        public IDbSet<BaseClass> BaseClass
        {
            get;
            set;
        }

        public IDbSet<ClassWithJsonB> ClassWithJsonB
        {
            get;
            set;
        }

        public IDbSet<ClassWithoutJsonB> ClassWithoutJsonB
        {
            get;
            set;
        }

        public DevartDbProvider() : base("DevartExample")
        {
            Database.Log = s => { System.Diagnostics.Debug.WriteLine(s); };
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            DevartDbProvider devartDbProvider = new DevartDbProvider();

            devartDbProvider.BaseClass.FirstOrDefault();

        }
    }
}

Выводит этот запрос:

SELECT 
"Limit1"."C1",
"Limit1"."Id",
"Limit1"."C2",
"Limit1"."C3"
FROM ( SELECT 
    "Extent1"."Id",
    CASE WHEN ( NOT (("Project2"."C1" = true) AND ("Project2"."C1" IS NOT NULL))) AND ( NOT (("Project1"."C1" = true) AND ("Project1"."C1" IS NOT NULL))) THEN '0X' WHEN ("Project2"."C1" = true) AND ("Project2"."C1" IS NOT NULL) THEN '0X0X' ELSE '0X1X' END AS "C1",
    CASE WHEN ( NOT (("Project2"."C1" = true) AND ("Project2"."C1" IS NOT NULL))) AND ( NOT (("Project1"."C1" = true) AND ("Project1"."C1" IS NOT NULL))) THEN CAST(NULL AS varchar) WHEN ("Project2"."C1" = true) AND ("Project2"."C1" IS NOT NULL) THEN "Project2"."Json" END AS "C2",
    CASE WHEN ( NOT (("Project2"."C1" = true) AND ("Project2"."C1" IS NOT NULL))) AND ( NOT (("Project1"."C1" = true) AND ("Project1"."C1" IS NOT NULL))) THEN CAST(NULL AS int) WHEN ("Project2"."C1" = true) AND ("Project2"."C1" IS NOT NULL) THEN CAST(NULL AS int) ELSE "Project1"."MyProperty" END AS "C3"
    FROM   "BaseClass" AS "Extent1"
    LEFT OUTER JOIN  (SELECT 
        "Extent2"."Id",
        "Extent2"."MyProperty",
        true AS "C1"
        FROM "ClassWithoutJsonb" AS "Extent2" ) AS "Project1" ON "Extent1"."Id" = "Project1"."Id"
    LEFT OUTER JOIN  (SELECT 
        "Extent3"."Id",
        "Extent3"."Json",
        true AS "C1"
        FROM "ClassWithJsonb" AS "Extent3" ) AS "Project2" ON "Extent1"."Id" = "Project2"."Id"
    LIMIT 1 
)  AS "Limit1"

Заранее спасибо.

1 Ответ

0 голосов
/ 22 октября 2018

Вы используете свободное отображение (не отображение XML), не так ли?Убедитесь, что в качестве типа столбца для соответствующих свойств задано значение jsonb: .HasColumnType ("jsonb");

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

...