sql - Slick:传入列进行更新

标签 sql database scala slick

假设我们有一个包含以下列的 FoodTable:NameCaloriesCarbsProtein。我有一个条目:Name = ChocolateCalories = 100Carbs = "10g"Protein = "2g".

我想知道是否有一种方法可以传入列名和更新的新值。例如,我想要一个类似于

def updateFood(food, columnName, value):
     table.filter(_.name === food).map(x => x.columnName).update(value)

Slick 似乎无法实现动态列?我想避免编写 SQL 查询,因为这可能会导致代码中出现安全漏洞或错误。真的没有办法吗?

我也不想传递整个对象进行更新,因为理想情况下,它应该是:

我想将列 X 更新为值 Y。我应该只需要传入对象的 ID、列和要更新到的值。

最佳答案

I'm wondering if there's a way to pass in a column name and a new value to update with

这在一定程度上取决于您希望“列名”是什么。为了保持安全,我建议让“列名”成为一个可以在表中选择列的函数。

在高层次上看起来像这样:

// Won't compile, but we'll fix that in a moment
def updateFood[V](food: Food, column: FoodTable => Rep[V], value: V): DBIO[Int] =
  foods.filter(_.name === food.name).map(column).update(value)

...我们会这样调用它:

updateFood(choc, _.calories, 99)

请注意“列名”是如何从 FoodTable 到具有某个值 V 的列的函数。然后您为 V 提供一个值,我们进行正常更新。

问题是 Slick 知道如何将某些类型的值(String、Int 等)映射到 SQL,但不是任何类型的值。上面的代码无法编译,因为 V 是不受约束的。

我们可以解决我在 V 上添加约束的问题,它通常会起作用:

// Will compile, will work for basic types
def updateFood[V : slick.ast.BaseTypedType](food: Food, column: FoodTable => Rep[V], value: V): DBIO[Int] =
 foods.filter(_.name === food.name).map(column).update(value)

但是,如果您有自定义列映射,它们将不匹配约束。我们需要更进一步,在范围内有一个隐式的形状:

def updateFood[V](food: Food, column: FoodTable => Rep[V], value: V)(implicit shape: Shape[_ <: FlatShapeLevel, Rep[V], V, _]): DBIO[Int] =
 foods.filter(_.name === food.name).map(column).update(value)

我认为 Shape 是 Slick 中一个额外的抽象层,高于 Rep[V]。 “形状级别”和其他细节的机制我无法解释,因为我还不了解它们! (有一个关于 Slick 设计的演讲,称为“提升嵌入中的多态记录类型”,您可以在 http://slick.lightbend.com/docs/ 找到)

最后一点:如果你真的希望列名是一个字符串或类似的东西,我建议将字符串(或以某种方式验证)模式匹配到 FoodTable => Rep 函数并在您的 SQL 中使用它。这将很棘手,因为您的值 V 将必须与您要更新的列的类型相匹配。

在我的脑海中,它可能看起来像这样:

def tryUpdateFood(food: Food, columnName: String, value: String): DBIO[Int] =
 columnName match {
   case "calories" => updateFood(food, _.calories, value.toInt)
   case "carbs" => updateFood(food, _.carbs, value)
   // etc...
   case unknown => DBIO.failed(new Exception(s"Don't know how to update $unknown columns"))
}

我可以想象更好的错误处理、更安全或更智能的值解析,但总的来说,以上内容是可行的。

有关处理动态问题的其他方法的提示,请查看“Slick 数据库应用程序的模式”(也列于:http://slick.lightbend.com/docs/)的演讲,在演示文稿的末尾有一个关于“动态排序”的部分".

关于sql - Slick:传入列进行更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49838709/

相关文章:

mysql - 使涉及小表和大表的条件 MySQL 连接变得高效

mysql - 根据条件连接两个表以及第二个表中的记录数

mysql - 获取MySQL中同一日期的最短时间

mysql - 从 kubernetes 将 mysql 主机列入白名单

scala - 使用 Slick 3 的动态排序

scala - 如何在 Scala 中将类型作为参数传递?

mysql查询来计算like运算符匹配每列的次数

mysql - Cakephp电子商务数据库设计

c# - 每 n 秒调用一次存储过程

scala - 如何测试 Scala Play 框架 websocket?