2017-04-11 88 views
0

我試圖設置一個外鍵約束可延遲,以便在插入查找/數據透視表時直到事務結束時纔會檢查它。但是,它在psql shell中有用,但它只是在代碼中不起作用。與在psql shell中一樣,我也在代碼中以begin開始一個事務。如何推遲Postgres中的外鍵約束

這是SQL:

create table campaign_r_company (
    campaign_id   uuid   not null references campaign(id) on delete cascade deferrable initially deferred, 
    company_id   varchar(32)  not null, 
    primary key (campaign_id, company_id) 
); 

下面的代碼:

tx, err := d.Begin() 
    if err != nil { 
    return err 
    } 


    err = h(tx) // there are two db queries will be called in this function 

    if err == nil { 
    err = tx.Commit() 
    } 

H(TX):

_, err := cxt.Exec(fmt.Sprintf(`INSERT INTO hp_campaign (%s) VALUES (%s)`, proplist("", campaignProps), arglist(1, len(campaignProps))), 
    id, v.Name, created, v.Updated, 
) 
if err != nil { 
    return err 
} 

v.Id = id 
v.Created = created 

if (opts & StoreOptionStoreRelated) == StoreOptionStoreRelated { 
    err := d.attach("company", "campaign_r_company", v.Companies, v.Id) 
    if err != nil { 
     return err 
    } 

} 

連接():

func (d *Database) attach(entityName string, tableName string, ids []string, campaignID string) error { 

    for _, id := range ids { 

     stmt := fmt.Sprintf(`INSERT INTO %s (%s) VALUES ($1, $2)`, tableName, fmt.Sprintf("campaign_id, %s_id", entityName)) 
     _, err := d.db.Exec(stmt, campaignID, id) 

     if err != nil { 
      return err 
     } 
    } 
    return nil 

} 

錯誤:

insert or update on table "campaign_r_company" violates foreign key constraint "campaign_r_company_campaign_id_fkey" 
+0

也許你的代碼在啓用autocommit的情況下運行?在哪一點你會得到那個錯誤信息? –

+0

那是怎麼回事?你開始交易,那麼你有兩個交易裏面,它結束了嗎?..什麼>//有兩個數據庫交易在這個功能意味着什麼?.. –

+0

是這是這個想法。我開始事務,然後調用一個包含兩個數據庫事務的函數。並最終結束它。 –

回答

0

從更新後的代碼和後續評論中,我們現在知道問題在於這兩個查詢分開執行而不是在單個事務中執行。

0

如果不使用手動事務管理,圍棋+ PG可以實現這個要求。在這種情況下,任何語句都是單個事務,並且在每個事務結束時檢查約束。所以引發異常。