Squeryl:如何使用部分更新来切换布尔列

时间:2013-03-06 09:15:08

标签: scala squeryl

假设我有一个类似的实体类:

case class MyEntity(some_flag: Boolean) extends KeyedEntity[Long]

我想使用Squeryl执行以下SQL更新:

update table_name set some_flag = not some_flag where id = 1

相关的Squeryl声明是做什么的?我已经尝试过了

def toggleFlag(id: Long) = inTransaction {
    update(table)(entity =>
        where(entity.id === id)
        set(entity.some_flag := !entity.some_flag)
    )
}

但这对数据库没有任何影响。

更新2: Squeryl documentation给出了部分更新示例,将整数值增加1:

update(songs)(s =>
  where(s.title === "Watermelon Man")
  set(s.title := "The Watermelon Man",
      s.year  := s.year.~ + 1)
)  

更新

我正在使用Squeryl 0.9.5-6与Scala 2.10和Play! 2.1

1 个答案:

答案 0 :(得分:1)

我从你的例子中做了一个小代码项目。问题是squeryl序列化了更新,但是它“吞下”了(!),产生了以下SQL:

 update MyEntity set
 some_flag = (some_flag)

基本上,squeryl在操作系统构建的树下构建,然后将其序列化为将发送到SQL适配器的字符串。

一般情况下,我检查它是否隔离更新语句并打印它(如squeryl那样):

    // From __update, Table.scala
    val dba = Session.currentSession.databaseAdapter
    val sw = new StatementWriter(dba)
    val o0 = _callbacks.beforeUpdate(o.asInstanceOf[AnyRef]).asInstanceOf[T]
    dba.writeUpdate(o0, this, sw, checkOCC)

复制我的类中的代码(用于调试目的)或直接在Table.scala中设置断点

要隔离语句,只需考虑更新的第二部分:

val s = ((entity: InsertTypeHere) =>
      where(entity.id === id)
      set(entity.some_flag := not entity.some_flag))

由于这个“技巧”,我发现对some_flag的引用被正确转换为类型为java.lang.Boolean的SelectElementReference,但是(!)没有被转换为PrefixOperator。这对我来说似乎是一个squeryl bug,但让我看看是否可以从你的代码中“修复”它。

更新:

挖掘squeryl代码,似乎缺少“not”运算符。幸运的是,很容易自己添加它!

     class NotExpression(val ast: ExpressionNode)(implicit val mapper: OutMapper[BooleanType])
        extends PrefixOperatorNode(ast, "not ", false)
                with LogicalBoolean with NestedExpression with TypedExpressionNode[BooleanType]

     def mynot(b: BooleanExpression[BooleanType]) = new NotExpression(b)

     transaction {
          update(table)(t => where(t.id === 3) set (t.some_flag := mynot(t.some_flag)))
     }

这会生成正确的SQL,至少在您的情况下如此。我会向squeryl提交补丁并征求意见。