假设我们有一个包含以下列的 FoodTable:Name
、Calories
、Carbs
、Protein
。我有一个条目:Name = Chocolate
、Calories = 100
、Carbs = "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/