2017-04-19 103 views
0

首先,請原諒我,如果我使用錯誤的條款,我非常新的PostgreSQL和NoSQL風格的數據存儲。繼續:在Postgres中插入帶有自動遞增字段的JSON列?

我正在使用npgsql將.NET項目連接到PostgreSQL數據庫。我們將它用作NoSQL文檔存儲,我們的表由id列的主鍵和data列中的jsonb對象組成,其他都沒有。

data列中,我們還想要一種生成每個插入時自動遞增的id字段的方法。這個ID不一定需要匹配主鍵,但這就是我正在工作的假設。

我已經能夠使用下面的腳本來使pgAdmin的這項工作:

drop table public.testjson; 
 
drop sequence public.testjson_id_seq; 
 

 
CREATE SEQUENCE public.testjson_id_seq 
 
    INCREMENT 1 
 
    MINVALUE 1 
 
    MAXVALUE 9223372036854775807 
 
    START 1 
 
    CACHE 1; 
 
ALTER TABLE public.testjson_id_seq 
 
    OWNER TO login; 
 

 
CREATE TABLE public.testjson 
 
(
 
    id bigint NOT NULL DEFAULT nextval('testjson_id_seq'::regclass), 
 
    data jsonb, 
 
    CONSTRAINT testjson_pkey PRIMARY KEY (id) 
 
); 
 
ALTER TABLE public.testjson 
 
    OWNER TO login; 
 

 

 
-- Insert data using currval -- 
 
INSERT INTO testjson (data) VALUES(to_jsonb('{"jsonid": '||currval('testjson_id_seq'::regclass)::bigint||', moreStuff: "all the stuff!"}')); 
 
INSERT INTO testjson (data) VALUES(to_jsonb('{"jsonid": '||currval('testjson_id_seq'::regclass)::bigint||', moreStuff: "all the stuff!"}')); 
 
INSERT INTO testjson (data) VALUES(to_jsonb('{"jsonid": '||currval('testjson_id_seq'::regclass)::bigint||', moreStuff: "all the stuff!"}')); 
 
INSERT INTO testjson (data) VALUES(to_jsonb('{"jsonid": '||currval('testjson_id_seq'::regclass)::bigint||', moreStuff: "all the stuff!"}')); 
 
select * from testjson 
 

 
-- Output -- 
 

 
id | data 
 
--------------------------------------------------------- 
 
1 | "{\"jsonid\": 1, moreStuff: \"all the stuff!\"}" 
 
2 | "{\"jsonid\": 2, moreStuff: \"all the stuff!\"}" 
 
3 | "{\"jsonid\": 3, moreStuff: \"all the stuff!\"}" 
 
4 | "{\"jsonid\": 4, moreStuff: \"all the stuff!\"}"

到目前爲止,一切都很好。我想我會重構這個,所以jsonid字段有自己的序列,並且使用nextval而不是currval(以防止導致重複的競爭條件),但問題不在於此。我在代碼方面無法複製這個問題。環顧其他questions這裏使我相信,這可能工作:

var crcmd = new NpgsqlCommand("INSERT INTO "+_schema+"."+table+" ("+JsonColumn+") VALUES (:json) RETURNING id;", _conn); 
 

 
var jsonData = getSerializedJsonData(thing, primaryKey); 
 
crcmd.Parameters.AddWithValue("json", NpgsqlDbType.Jsonb, jsonData); 
 

 
returnId = (long) crcmd.ExecuteScalar(); 
 

 
... 
 

 
private string getSerializedJsonData<T>(T thing, string primaryKey, string tableSeq) 
 
{ 
 
    var jsonThing = JsonConvert.SerializeObject(thing); 
 

 
    var bracketIndex = jsonThing.IndexOf('{'); 
 
    var thingPrefix = jsonThing.Substring(0, bracketIndex + 1); 
 
    var thingData = jsonThing.Substring(bracketIndex + 1); 
 
    var pkEntry = "\"" + primaryKey +"\": currval('" + tableSeq + '::regclass)::bigint, "; 
 
    jsonThing = thingPrefix + pkEntry + thingData; 
 
    return jsonThing; 
 
}

但是當我嘗試對其進行測試,以下異常被拋出:

Npgsql.PostgresException: 22P02: invalid input syntax for type json; Token "currval" is invalid

任何想法我錯了?

回答

0

我明白了。原來有兩件事我需要修復。

第一個是轉換到jsonb。我沒有注意過,但如果你看看我的postgres輸出,data列將被保存爲一個字符串,而不是一個jsonb對象。通過將to_jsonb('...')替換爲('...')::jsonb可以很容易地解決這個問題。

第二個任務是讓它在C#中工作。爲了做到這一點,我不得不改變NpgsqlCommand的創建方式:爲了訪問currval值,我必須將命令文本作爲原始文本傳遞,而不是像我原本試圖做的那樣將其參數化。所以最後,工作代碼看上去更像是這樣的:

var jsonData = getSerializedJsonData(thing, primaryKey); 
 
var crcmd = new NpgsqlCommand("INSERT INTO "+_schema+"."+table+" ("+JsonColumn+") VALUES (('+jsonData+')::jsonb) RETURNING id;", _conn); 
 

 
returnId = (long) crcmd.ExecuteScalar(); 
 

 
... 
 

 
private string getSerializedJsonData<T>(T thing, string primaryKey, string tableSeq) 
 
{ 
 
    var jsonThing = JsonConvert.SerializeObject(thing); 
 

 
    var bracketIndex = jsonThing.IndexOf('{'); 
 
    var thingPrefix = jsonThing.Substring(0, bracketIndex + 1); 
 
    var thingData = jsonThing.Substring(bracketIndex + 1); 
 
    var pkEntry = "\"" + primaryKey +"\": currval('" + tableSeq + '::regclass)::bigint, "; 
 
    jsonThing = thingPrefix + pkEntry + thingData; 
 
    return jsonThing; 
 
} 
 

 
-- Output (truncated) -- 
 
id | data 
 
-------------------------------------------------------- 
 
1 | { IsActive: true, "DisplayName": "configUser", "UserLoginId": 1", "PasswordHash":... 
 
2 | { IsActive: true, "DisplayName": "WDCGVBNESSAULSAZLIVR", "UserLoginId": 2", "Pass... 
 
3 | { IsActive: false, "DisplayName": "UJMFANMOSHPNDQSEUEGL", "UserLoginId": 3", "Pas... 
 
4 | { IsActive: true, "DisplayName": "SOQDFTZVHPHXIXDVQJTS", "UserLoginId": 4", "Pass... 
 
5 | { IsActive: true, "DisplayName": "WFPUMCRBRPDHSQALMKPW", "UserLoginId": 5", "Pass... 
 
6 | { IsActive: true, "DisplayName": "HVBEGQSSFJWCJYCCLMXI", "UserLoginId": 6", "Pass...

+0

將數據插入直接作爲字符串打破了數據庫的基本規則查詢。你有沒有找到更好的解決方案? – piojo