I have a table, HVACLoads
with JSON columns CoolingLoads
and HeatingLoads
in PostgreSQL DB. I am just changing the properties of JSON using PostgreSQL JSON functions to update the inner properties by calling the function with migration builder during the Ef Core migration with c#. For example, the data structure for cooling and heating loads is below.
{
"Roof": {
"Total": 0,
"Latent": 23,
"SensibleTotal": 0,
"PercentOfTotal": 0,
"SensibleDelayed": 1,
"SensibleInstant": 0,
"SensibleReturnAir": 0
},
...
....
}
And below is the resulting structure
{
"Roof": {
"Total": power { scalar: 0, unit: "btuh"},
"Latent": power { scalar: 23, unit: "btuh"},
"SensibleTotal": power { scalar: 0, unit: "btuh"},
"PercentOfTotal": 0,
"SensibleDelayed": power { scalar: 1, unit: "btuh"},
"SensibleInstant": power { scalar: 0, unit: "btuh"},
"SensibleReturnAir": power { scalar: 0, unit: "btuh"}
},
...
....
}
I am calling the below PostgreSQL function from migration and trying to update the properties.
protected override void Up(MigrationBuilder migrationBuilder)
{
var options = new DbContextOptionsBuilder<APIDbContext>()
.UseNpgsql(Startup.Configuration["ConnectionStrings:Postgres"])
.Options;
using var ctx = new APIDbContext(options);
ctx.Database.OpenConnection();
migrationBuilder.Sql(@"
CREATE OR REPLACE FUNCTION set_loads(object_name text, field_name text)
RETURNS void AS
$$
DECLARE
query text;
cooling_power_value numeric;
heating_power_value numeric;
BEGIN
IF field_name = 'PercentOfTotal' THEN
query := 'UPDATE """"HvacLoadReports""""
SET ' || field_name || ' = ''' || PercentOfTotal::numeric || ''',
""""CoolingLoads"""" = jsonb_set(""""CoolingLoads"""", ''{""""''' || object_name || '''"""",""""''' || field_name || '''""""}'', to_jsonb((""""CoolingLoads""""->>''""""' || object_name || '""""''->>''""""' || field_name || '""""'')::numeric), false),
""""HeatingLoads"""" = jsonb_set(""""HeatingLoads"""", ''{""""''' || object_name || '''"""",""""''' || field_name || '''""""}'', to_jsonb((""""HeatingLoads""""->>''""""' || object_name || '""""''->>''""""' || field_name || '""""'')::numeric), false)';
ELSE
cooling_power_value := (""""CoolingLoads""""->>''""""' || object_name || '""""'',''""scalar""'')::numeric;
heating_power_value := (""""HeatingLoads""""->>''""""' || object_name || '""""'',''""scalar""'')::numeric;
query := 'UPDATE """"HvacLoadReports""""
SET """"CoolingLoads"""" = jsonb_set(""""CoolingLoads"""", ''{""""''' || object_name || '''"""",""""''' || field_name || '''""""}'', to_jsonb((""""CoolingLoads""""->>''""""' || object_name || '""""''->>''""""' || field_name || '""""'')::numeric), false),
""""HeatingLoads"""" = jsonb_set(""""HeatingLoads"""", ''{""""''' || object_name || '''"""",""""''' || field_name || '''""""}'', to_jsonb((""""HeatingLoads""""->>''""""' || object_name || '""""''->>''""""' || field_name || '""""'')::numeric), false),
""""CoolingLoads"""" = jsonb_set(""""CoolingLoads"""", ''{""""''' || object_name || '''"""",""""power""""}'', ''{""""scalar"""": '' || cooling_power_value || '', """"unit"""": """"btuh""""}'', true),
""""HeatingLoads"""" = jsonb_set(""""HeatingLoads"""", ''{""""''' || object_name || '''"""",""""power""""}'', ''{""""scalar"""": '' || heating_power_value || '', """"unit"""": """"btuh""""}'', true)';
END IF;
EXECUTE query;
END
$$ LANGUAGE plpgsql;
");
Calling the above function using the below code inside the migration Up
method:
migrationBuilder.Sql($"SELECT set_loads('{Roof}', '{Total}');");
But getting an error like
zero-length delimited identifier at or near """"
Could anyone please point me to why I am getting the above error?
Looks like you have escaped (doubled up) double-quotes one times too many. Try this as SQL string in double-quotes:
"
CREATE OR REPLACE FUNCTION set_loads(object_name text, field_name text)
RETURNS void
LANGUAGE plpgsql AS
$func$
DECLARE
query text;
cooling_power_value numeric;
heating_power_value numeric;
BEGIN
IF field_name = 'PercentOfTotal' THEN
query := $q$
UPDATE ""HvacLoadReports""
SET ""PercentOfTota"" = jsonb_set(""PercentOfTota"", 'Roof'
, (SELECT jsonb_object_agg(
key
, CASE WHEN key = 'PercentOfTotal'
THEN value
ELSE jsonb_set('{""power"": {""scalar"": 0, ""unit"": ""btuh""}}', '{power, scalar}', value)
END)
FROM jsonb_each(""PercentOfTota"" -> 'Roof')))$q$;
ELSE
-- ... more
END IF;
-- RAISE NOTICE '%', query; -- to debug
EXECUTE query;
END
$func$;
"
I simplified so that all values nested in the key 'Roof' are replaced with the verbose form - except when the key is 'PercentOfTotal'.
Also note the use of dollar-quotes to preserve plain single-quotes. See:
Your life with Postgres is easier with legal, lower-case, unquoted identifiers. See: