Sql Slick:传入列以进行更新

Sql Slick:传入列以进行更新,sql,database,scala,slick,Sql,Database,Scala,Slick,假设我们有一个包含以下列的食物表:名称,卡路里,碳水化合物,蛋白质。我有一个关于Name=Chocolate,carries=100,Carbs=“10g”和Protein=“2g”的条目 我想知道是否有方法传入列名和新值以进行更新。例如,我想要一个如下的方法 def updateFood(food, columnName, value): table.filter(_.name === food).map(x => x.columnName).update(value) 似乎

假设我们有一个包含以下列的食物表:
名称
卡路里
碳水化合物
蛋白质
。我有一个关于
Name=Chocolate
carries=100
Carbs=“10g”
Protein=“2g”
的条目

我想知道是否有方法传入列名和新值以进行更新。例如,我想要一个如下的方法

def updateFood(food, columnName, value):
     table.filter(_.name === food).map(x => x.columnName).update(value)
似乎使用Slick不可能使用动态列?我希望避免编写SQL查询,因为这可能会导致代码中的安全缺陷或bug。真的没有办法吗

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

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

我想知道是否有一种方法可以传递一个列名和一个新值来更新

这取决于您希望“列名”是什么。为了维护安全性,我建议将“column name”作为一个可以选择表中某一列的函数

在一个很高的层次上,看起来是这样的:

// 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)
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"))
}
…我们称之为:

// 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)
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"))
}
请注意,“列名”是如何从
FoodTable
到某个值的列
V
的函数。然后为
V
提供一个值,然后我们进行正常更新

问题是,Slick知道如何将某些类型的值(String、Int等)映射到SQL中,但不知道如何将任何类型的值映射到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)
我可以想象更好的错误处理、更安全或更智能的值解析,但在概述中,上述方法可以奏效


有关处理动态问题的其他方法的提示,请参阅“Slick数据库应用程序的模式”(也列在:)一节,在演示的末尾有一节是关于“动态排序”的。我想指出,这是一种惯用的错误方法(传递列名和列值)因为在这种情况下,您将失去类型安全性。这和构造SQL查询一样糟糕。我不知道您的实体是什么样子的,但也许您可以为DAO中的每个字段保留一些合理数量的更新方法?