Я использую Option как результат при извлечении объекта из базы данных с идентификатором?

Я сделал определение, которое извлекает пользователя из базы данных.

 def user(userId: Int) : User = database withSession {
    (for{
      u <- Users if u.id === userId} 
    yield u).first
  }

Потенциально база данных может вернуть пустой список, если используется с несуществующим идентификатором пользователя.
Однако я не вижу, когда будет предоставлен несуществующий идентификатор пользователя. Например, мой идентификатор пользователя извлекается из вошедшего в систему пользователя. И если предоставлен несуществующий идентификатор пользователя, то я думаю, что можно жестко отклонить запрос.

Есть предположения?


person Farmor    schedule 29.01.2013    source источник
comment
Очень похожий вопрос на stackoverflow.com/questions/3886781/   -  person Kristian Domagala    schedule 30.01.2013


Ответы (3)


Нет, это не нормально, чтобы не выполнить запрос:

def user(userId: Int) : Option[User] // is OK
def user(userId: Int) : Either[String,User] // is OK
def user(usedId: Int) : User // is not OK

или же вы можете создать тип (концепцию), который инкапсулирует целое число, которое гарантирует, что это действительный идентификатор пользователя (при рождении).

sealed case class UserId(u:Int) //extends AnyVal // If it's scala 2.10.0

object UserId {
    def get(i:Int) : Option[UserId] = //some validation

} /// ....

def  user(userId:UserId) : User //is OK // well it depends on the semantic of user destruction.

Когда вы делаете определение, вы должны убедиться, что существует правильное отношение между доменом (this и args) вашей функции и доменом кода (результатом).

В любом случае, не стесняйтесь печатать (создавать концепции), это поможет вам рассуждать о вашем коде.


Почему def user(userId: Int) :User не подходит?

Потому что отношение между элементами Integer к элементам User не существует. Что, если все идентификаторы пользователей — положительные целые числа, но вы запрашиваете user(-10)? (этого не произойдет, верно?) Должен ли этот вызов вызвать исключение? Или вернуть ноль?

Если вы считаете, что он должен возвращать значение null, верните параметр Option, он инкапсулирует потенциально отсутствующее соответствие.

Если вы считаете, что это должно вызвать исключение, верните:

  • Validation[SomethingRepresentingAnError, User] (скалаз),
  • Either[SomethingRepresentingAnError, User] (скала 2.7, 2.8, 2.9)
  • или Try[User] (scala 2.10)

Расширенные типы возвращаемых данных помогут вам правильно использовать API.

Кстати, Scala не использует проверенное исключение, поэтому вы не можете использовать исключение в качестве альтернативного результата. Исключение должно быть сохранено для действительно исключительного поведения (как исключения во время выполнения).

Смотрите также :

  • http://www.scala-lang.org/api/current/index.html#scala.util.control.Exception$
person jwinandy    schedule 29.01.2013
comment
Хотите уточнить, почему это не нормально? Официальная документация SLICK использует этот подход. - person Farmor; 29.01.2013
comment
Это долгая дискуссия об основах функционального программирования. Типы — это понятия, а функции — отношения между понятиями. Это также относится к хорошему программированию ООП. (Мне не все равно, но я в пути) - person jwinandy; 29.01.2013
comment
Я должен зарезервировать изложение документации, так как оно было встроено в какой-то код шаблона. - person Farmor; 29.01.2013

Я думаю, что всегда полезно возвращать Option[] при выборке данных по идентификатору. Вы не можете быть уверены, что пользователь с таким идентификатором существует. напр. другой запрос удалил этого пользователя или кто-то пытался подделать ваши входные данные. База данных — это внешняя система для вашего приложения, и если вы знаете, как восстанавливаться после таких сбоев, вы должны это сделать. Особенно в Scala, где Option — хороший инструмент для такой задачи.

person kompot    schedule 29.01.2013

Option — это самый минималистичный способ представления возвращаемого значения из некоторых вычислений, которые могут завершиться ошибкой. Генерация исключений или возврат null допустимы только при работе с Java-кодом, и ваши руки каким-то образом связаны существующим API (и когда ваш код вызывается из Java-кода).

Следующим шагом от Option будет Either[FailureIndication, SuccessValue].

Дальнейшее улучшение — Validation ScalaZ.

person Randall Schulz    schedule 29.01.2013