2016-09-16 68 views
0

我想實現一個方法,創建一個用戶,如果它還不存在。如果確實存在,則應該返回用戶。如何在未來解壓Option?

這裏是我的代碼:

def createUserIfNotExists(user: User) = { 
for { 
    count <- userService.count(Some(user)) 
    user <- if (count == 0) createUser(user) else userService.findOneByName(user.name) 
} yield user 
} 

我的問題是findOneByName回報Future[Option[User]]createUser回報Future[User]所以類型不匹配。

如何解開Future[Option[User]]Future[User]或在有None的情況下拋出異常?

+1

「for」理解沒有任何用處。 – jwvh

+0

@jwvh爲什麼?你能解釋一下嗎? –

+0

SO評論將不會允許我呈現格式化的代碼,但CNTL-複製以下內容並插入空格:'def createUserIfNotExists(user:User)= if(userService.count(Some(user))> 0) userService .findOneByName(user.name) else createUser(user)' – jwvh

回答

2

使createUser也返回Future[Option[_]]

def createUserIfNotExists(user: User) = { 
    for { 
    count <- userService.count(Some(user)) 
    userOpt <- if (count == 0) createUser(user).map(Some(_)) else userService.findOneByName(user.name) 
    } yield userOpt 
} 

您可以在選擇做.get因爲如果計數不爲零,這意味着用戶在數據庫中絕對可用。

def createUserIfNotExists(user: User) = { 
    for { 
    count <- userService.count(Some(user)) 
    user <- if (count == 0) createUser(user) else userService.findOneByName(user.name).map(_.get) 
    } yield user 
} 

首先嚐試獲取用戶如果沒有創建用戶

def createUserIfNotExists(user: User) = { 
for { 
    userOpt <- userService.findOneByName(user.name) 
    user <- userOpt match { 
     case Some(value) => value 
     case None => createUser(user).map(_ => user) 
    } 
} yield user 
} 

注意,爲確保在並行數據庫操作的情況下正確性,強烈建議執行上面的代碼在transaction

+0

你的第三個答案不會編譯。你在混合類型的理解。 – wheaties

+0

@wheaties ..編輯答案.. PLease檢查...我沒有;不用擔心類型,因爲在滿足編譯器的問題中沒有給出完整的代碼留給用戶。我有興趣給出主要想法(只是解決方案的癥結所在) – pamu

2

只是mapcreateUser函數返回類型:

if (count == 0) createUser(user).map(Option(_)) else userService.findOneByName(user.name) 

說的findOneByName返回類型包含Option提示您可能沒有用戶的事實。這種類型的存在是有原因的,所以扔掉它是不好的,因爲它會拋棄信息。

1

使用findOneByName函數直接使您不必查詢數據庫兩次:

val res: Future[UserDB] = 
    userService 
    .findOneByName(user.name) 
    // if the option in the future is not empty, return its content 
    // otherwise create a new user 
    .flatMap(_.map(Future.successful).getOrElse(createUser(user)))