2017-08-31 51 views
1

我已經有一個單一的實體create方法:斯卡拉油滑。事務插入批次

override def createEntity(entity: Entity) = 
    db.run(
    (for { 
     existing <- Entity.filter(e => e.id === entity.id).result //Check, if entity exists 
     e <- if (existing.isEmpty) 
      (Entity returning Entity) += Entity(entity.id, entity.name) 
      else { 
      throw new DuplicateException(s"Create failed: entity already exists") 
      } 
     } yield e).transactionally 
    ) 

如何重新爲事務創建實體的列表中選擇此方法?

//Doesn't work 
override def createEntities(entities : List[model.Entity]) = { 
    db.run(
     (for { 
      e <- entities 
     } 
     yield createEntity(e) 
    ).transactionally 
    ) 
} 

我是新手在slick :(

PS對不起,我的英語

回答

1

你的問題的根源是,你想內從所謂的代碼執行多個db.run秒(在你的createEntity申報)db.run(在createEntities聲明)。這些外部內部db.run在概念上是不相關的,因此不會在同一個事務中執行。

觀點有點

爲了更好地理解正在發生的事情,以及如何應對這樣的情況下,我們不得不說說單子,具體DBIOAction(我會盡量解釋概念是怎麼回事因爲嚴格的解釋會花費太多時間,而且與解決方案無關)。

關於DBIOAction的一種思考方式是作爲解釋如何執行查詢和從db獲取結果的步驟(代碼)的固定列表。 db.run確實執行此列表。

需要注意的重要一點是,此列表包含要在數據庫(SQL查詢)以及本地jvm(運行時scala函數對象)中執行的步驟(代碼)。

此外,此列表中的每個元素(代碼段)都依賴於之前的輸入或前一個輸入。這一切都是通過一系列的map/flatMapsfor表達式被去掉)粘在一起的。這看起來是這樣的:

(1) sql code (generates input for (2)) 
(2) jvm code (gets input from (1), and generates (3)) 
(3) sql code (generates input for (4)) 
(4) jvm code (gets input from (3), and generates (5)) 
... 

注意,普通的JVM代碼被織進這個名單,只要它產生下一步指令可以是任何東西(或提供傳遞給map代碼的情況下,最終結果) 。因爲這使得整個列表的動態行爲(即,每個「jvm代碼」步驟都可以影響在路上的計算),所以一般而言(並且因此DBIOAction)具有巨大的表現力。

你可以在「jvm code」步驟中做任何事情的副作用是,你也可以產生和執行新的不相關的計算列表(這是你正在嘗試做的),這可能是好的,但也可以令人困惑的是,如果你沒有考慮單一構成的話。

那麼,你實際上可以做些什麼來解決問題呢?

如果您關注的是代碼重用我建議你擺脫db.run S和提取DBIOAction以後可以db.runcreateEntity和(一些調整)的createEntities

你應該能夠在你的代碼重寫一些類似的(我沒有實體的確切版本,因此其視爲僞代碼):

def createQuery(entity: Entity) = (for { 
    existing <- Entity.filter(e => e.id === entity.id).result 
    e <- if (existing.isEmpty) 
     (Entity returning Entity) += Entity(entity.id, entity.name) 
    else { 
     throw new DuplicateException(s"Create failed: entity already exists") 
    } 
    } yield e) 


    def createEntity(entity: Entity) = db.run(createQuery(entity)) 

    def createEntities(entities : List[model.Entity]) = { 
    db.run(DBIO.sequence(entities.map(createQuery(_))).transactionally) 
    } 

DBIO.sequence結合器的應用程序列表的DBIOAction s並將transactionally應用於實際的db.run之前的結果。

旁註

如果你有在你的架構控制我建議你在代碼中移動從實體創建實施「唯一ID」約束到數據庫。

+0

我明白了!謝謝! – Oleg