Как создать запрос Anorm, чтобы пропустить обновление значений None в БД (Scala)

Я использую Anorm (2.5.1) в своем приложении Play+Scala (2.5.x, 2.11.11). Я довольно часто сталкиваюсь с проблемой, когда, если значение аргумента класса case равно None, я не хочу, чтобы это значение параметра вставлялось/обновлялось в базу данных SQL. Например:

case class EditableUser(
    user_pk: String,
    country: Option[String],
    country_phone_code: Option[Int],
    phonenumber: Option[String],
    emailid: Option[String],
    format_all: Option[String]
)
....
val eUser: EditableUser = EditableUser("PK0001", None, None, None, Some("[email protected]"), Some("yes"))
...
    SQL"""
       update #$USR SET
       COUNTRY=${eUser.country},
       COUNTRY_PHONE_CODE=${eUser.country_phone_code},
       PHONENUMBER=${eUser.phonenumber},
       EMAILID=${emailid},
       FORMAT_ALL=${format_all}
       where (lower(USER_PK)=lower(${eUser.user_pk}))
    """.execute()

Здесь, когда значение равно None, Anorm вставит «null» в соответствующий столбец в базе данных SQL. Вместо этого я хочу написать запрос таким образом, чтобы Anorm пропускал обновление тех значений, которые равны None, т.е. не перезаписывал.


person NKM    schedule 11.06.2018    source источник


Ответы (2)


Вы должны использоватьboundStatements/preparedStatement и при установке значений для запроса не устанавливать значения для столбцов, которых нет.

Например

SQL(
  """
select * from Country c 
join CountryLanguage l on l.CountryCode = c.Code 
where c.code = {countryCode};
  """
).on("countryCode" -> "FRA")

Или в вашем случае:

import play.api.db.DB
import anorm._

val stat = DB.withConnection(implicit c =>
  SQL("SELECT name, email FROM user WHERE id={id}").on("id" -> 42)
)

При написании запроса вы проверяете, не равно ли значение, которое вы собираетесь вставить (x-> something), None, если это хорошо, не ставьте его, поэтому вы не будете обновлять значения, которые равны нулю.

person Raman Mishra    schedule 11.06.2018
comment
Ваш ответ не касался моего вопроса. Я ищу поддержку в запросе Anorm, который на данный момент недоступен. Я также проверил вокруг с другими людьми. - person NKM; 13.06.2018
comment
Это позволяет подготовить оператор перед привязкой, чтобы не подготавливать поле, которое не будет привязано к параметру. - person cchantep; 14.06.2018
comment
Дайте мне знать, если мне нужно удалить ответ - person Raman Mishra; 14.06.2018

Без возможности (или библиотеки) доступа к именам самих атрибутов все равно было бы возможно, хотя и немного неуклюже в некоторых кругах, динамически создавать оператор обновления в зависимости от значений, которые присутствуют в классе case:

case class Foo(name:String, age:Option[Int], heightCm:Option[Int])
...
def phrase(k:String,v:Option[Int]):String=if (v.isDefined) s", $k={$k}" else ""

def update(foo:Foo) : Either[String, Foo] = DB.withConnection { implicit c =>
  def stmt(foo:Foo) = "update foo set "+
    //-- non option fields
    "name={name}" +
    //-- option fields
    phrase("age", foo.age) +
    phrase("heightCm", foo.heightCm)

  SQL(stmt(foo))
    .on('name -> name, 'age -> age, 'heightCm -> heightCm)
    .executeUpdate()

Символы, отсутствующие в фактически отправленном SQL, можно указать в файле on. Необходимо также учитывать другие типы данных.

person wwkudu    schedule 01.07.2018