左连接上的UnexpectedNullableFound

时间:2016-04-05 15:55:04

标签: sql scala anorm

您好我遇到了一个UnexpectedNullableFound的问题。列可以返回空值,但我将其映射(如下所示)作为选项,因此不应该导致问题。这适用于我从该表中获取的其他字段。如果我删除' pe.company AS admin_company'和代码中的相关映射,我没有任何问题。

如果admin_company为null,我会遇到此问题。如果没有,它执行得很好。

我已经阅读了很多相关问题,但是在这里找不到任何解决方案。

有关于此的任何想法吗?感谢

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[RuntimeException: ColumnName(test_users.company,Some(admin_company))]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:265)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:191)
    at play.api.GlobalSettings$class.onError(GlobalSettings.scala:179)
    at play.api.DefaultGlobal$.onError(GlobalSettings.scala:212)
    at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:94)
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3.applyOrElse(PlayDefaultUpstreamHandler.scala:266)
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3.applyOrElse(PlayDefaultUpstreamHandler.scala:262)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:343)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
    at play.api.libs.iteratee.Execution$trampoline$.executeScheduled(Execution.scala:109)
    at play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:71)
    at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40)
    at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248)
    at scala.concurrent.Promise$class.complete(Promise.scala:55)
    at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:23)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:397)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
Caused by: java.lang.RuntimeException: ColumnName(test_users.company,Some(admin_company))
    at scala.sys.package$.error(package.scala:27)
    at anorm.SqlRequestError$class.toFailure(Anorm.scala:20)
    at anorm.UnexpectedNullableFound.toFailure(Anorm.scala:37)
    at anorm.Sql$$anonfun$asTry$2$$anonfun$apply$7.apply(Anorm.scala:303)
    at anorm.Sql$$anonfun$asTry$2$$anonfun$apply$7.apply(Anorm.scala:303)
    at anorm.SqlResult$class.fold(SqlResult.scala:23)
    at anorm.Error.fold(SqlResult.scala:31)
    at anorm.Sql$$anonfun$asTry$2.apply(Anorm.scala:303)
    at anorm.Sql$$anonfun$asTry$2.apply(Anorm.scala:303)
    at scala.util.Success.flatMap(Try.scala:230)
    at anorm.Sql$.asTry(Anorm.scala:303)
    at anorm.WithResult$class.as(SqlResult.scala:120)
    at anorm.SimpleSql.as(SimpleSql.scala:6)
    at com.company.test.user.service.testUserService$$anonfun$findByEmail$1.apply(testUserService.scala:229)
    at com.company.test.user.service.testUserService$$anonfun$findByEmail$1.apply(testUserService.scala:214)
    at play.api.db.DefaultDatabase.withConnection(Databases.scala:155)
    at play.api.db.DefaultDatabase.withConnection(Databases.scala:149)
    at play.api.db.DB$.withConnection(DB.scala:61)
    at com.company.test.user.service.testUserService.findByEmail(testUserService.scala:214)
    at com.company.test.controllers.testLoginController.checkPasswordAndSaveUserInSession(testLoginController.scala:128)

这是相关代码:

def findByUserId(userId: Long): TestUser = {
DB.withConnection { implicit connection =>
  SQL"""
      SELECT s.test_users_id, s.test_users_email AS user_email, s.test_users_first_name, s.test_users_second_name, s.company, s.useas, s.Stripe_CUSTOMER_ID,
  s.is_invoice_customer, s.test_users_invoice_email,
  s.password_hash, s.salt, s.invoice_address,
        s.time_zone, s.last_payment_date AS user_last_payment_date, s.sign_up_date, s.test_role AS user_test_role, s.num_seats, (SELECT COUNT(*) FROM test_users_paid_for WHERE test_users_admin_id = $userId) AS paid_for_seats,
  s.syndication_access_manager, p.test_users_admin_id, pe.last_payment_date AS admin_last_payment_date, pe.test_role AS admin_test_role,
  s.first_payment_date AS first_payment_date, pe.first_payment_date AS admin_first_payment_date, pe.test_users_email AS admin_email, pe.company AS admin_company, s.utm_source, s.utm_medium, s.utm_campaign, s.sf_exec, s.bounced_email,
  s.vat_number

  FROM test_users AS s
  LEFT JOIN test_users_paid_for AS p ON email_users_email = s.test_users_email
  LEFT JOIN test_users AS pe ON p.test_users_admin_id = pe.test_users_id

    WHERE s.test_users_id = $userId
      """.as(simple.single)
}
}

val customer = {
get[Long]("test_users_id") ~
  get[Option[Long]]("test_users_admin_id") ~
  get[String]("company") ~
  getAliased[Option[String]]("admin_company") ~
  getAliased[Option[DateTime]]("first_payment_date") ~
  getAliased[Option[DateTime]]("admin_first_payment_date") ~
  getAliased[Option[String]]("user_test_role") ~
  getAliased[Option[String]]("admin_test_role") map {
  case testUserId ~ testUsersAdminId ~ company ~ adminCompany ~ firstPaymentDate ~ adminFirstPaymentDate ~ testRole ~ admintestRole =>
    if(testUsersAdminId.isDefined){
      getCompanyCustomer(testUsersAdminId, adminCompany, adminFirstPaymentDate, admintestRole)
    } else {
      getCompanyCustomer(Some(testUserId), Some(company), firstPaymentDate, testRole)
    }
}
}

  def getCompanyCustomer(testUsersAdminId: Option[Long], adminCompany: Option[String], adminFirstPaymentDate: Option[DateTime], admintestRole: Option[String]): Option[CompanyCustomer] = {
for {
  id <- testUsersAdminId
  company <- adminCompany
  firstPaymentDate <- adminFirstPaymentDate
  testRole <- admintestRole
} yield CompanyCustomer(id, company, firstPaymentDate, testRole)
}

val simple = {
get[Long]("test_users_id") ~
  getAliased[String]("user_email") ~
  get[String]("test_users_first_name") ~
  get[String]("test_users_second_name") ~
  get[String]("company") ~
  customer ~
  get[String]("useas") ~
  get[Option[String]]("Stripe_CUSTOMER_ID") ~
  get[Boolean]("is_invoice_customer") ~
  get[Option[String]]("test_users_invoice_email") ~
  get[Array[Byte]]("password_hash") ~
  get[Array[Byte]]("salt") ~
  get[String]("invoice_address") ~
  get[Option[String]]("time_zone") ~
  getAliased[DateTime]("user_last_payment_date") ~
  get[DateTime]("sign_up_date") ~
  getAliased[Option[String]]("user_test_role") ~
  get[Option[Int]]("num_team") ~
  get[Int]("paid_for_team") ~
  get[Option[Long]]("test_users_admin_id") ~
  getAliased[Option[DateTime]]("admin_last_payment_date") ~
  getAliased[Option[String]]("admin_test_role") ~
  getAliased[Option[DateTime]]("first_payment_date") ~
  getAliased[Option[String]]("admin_email") ~
  getAliased[Option[DateTime]]("admin_first_payment_date") ~
  getAliased[Option[String]]("utm_source") ~
  getAliased[Option[String]]("utm_medium") ~
  getAliased[Option[String]]("utm_campaign") ~
  getAliased[Option[String]]("sf_exec") ~
  get[Option[Long]]("access_manager") ~
  get[Option[String]]("vat_number") ~
  getAliased[Boolean]("bounced_email") map {
  case testUsersId ~ userEmail ~ testUsersFirstName ~ testUsersSecondName
    ~ company ~ adminCustomer ~ useAs ~ stripeCustomerId ~ isInvoiceCustomer ~ secondContactEmail ~ passwordHash ~ salt ~
    invoiceAddress ~ timeZone ~ lastPaymentDate ~ signUpDate ~ testRole ~ numteam ~ paidForteam ~ testUsersAdminId ~ adminLastPaymentDate ~ admintestRole ~ firstPaymentDate ~
    adminEmail ~ adminFirstPaymentDate ~ utmSource ~ utmMedium ~ utmCampaign ~ sfExec ~ syndicationAccessManagerId ~ vatNumber ~ bouncedEmail =>
    testUser(testUsersId, userEmail, testUsersFirstName,
      testUsersSecondName, company, adminCustomer, useAs, invoiceAddress,
      stripeCustomerId,
      isInvoiceCustomer,
      secondContactEmail,
      passwordHash.toVector, salt.toVector,
      teamLastPaymentDate(lastPaymentDate, adminLastPaymentDate, testUsersAdminId, stripeCustomerId), new DateTime(signUpDate, DateTimeZone.UTC),
      testRoleFromTeam(testRole, testUsersAdminId, stripeCustomerId, admintestRole), paidByOtherUser(testUsersAdminId, stripeCustomerId), numteam.getOrElse[Int](0), //
      getSeatCount(paidForteam), timeZone.flatMap(getSafeTimeZone),
      firstPaymentDateFromTeam(testUsersAdminId, stripeCustomerId, firstPaymentDate, adminFirstPaymentDate), adminEmail, utmSource, utmMedium, utmCampaign,
      sfExec, syndicationAccessManagerId, vatNumber, bouncedEmail)
}
}

1 个答案:

答案 0 :(得分:2)

我的问题的解决方案是将所有别名更改为大写。现在使用Anorm 2.4

可以正常使用

我的新代码如下,它还包括一些重构,但大致相同。

val simple = {
get[Long]("test_users_id") ~
  getAliased[String]("USER_EMAIL") ~
  get[String]("test_users_first_name") ~
  get[String]("test_users_second_name") ~
  getAliased[String]("USER_COMPANY") ~
  get[String]("useas") ~
  get[Option[String]]("Stripe_CUSTOMER_ID") ~
  get[Boolean]("is_invoice_customer") ~
  get[Option[String]]("test_users_invoice_email") ~
  get[Array[Byte]]("password_hash") ~
  get[Array[Byte]]("salt") ~
  get[String]("invoice_address") ~
  get[Option[String]]("time_zone") ~
  getAliased[DateTime]("USER_LAST_PAYMENT_DATE") ~
  get[DateTime]("sign_up_date") ~
  getAliased[Option[String]]("USER_SPIKE_ROLE") ~
  get[Option[Int]]("num_team") ~
  get[Int]("paid_for_team") ~
  get[Option[Long]]("test_users_admin_id") ~
  getAliased[Option[DateTime]]("ADMIN_LAST_PAYMENT_DATE") ~
  getAliased[Option[String]]("ADMIN_SPIKE_ROLE") ~
  getAliased[Option[DateTime]]("FIRST_PAYMENT_DATE") ~
  getAliased[Option[String]]("ADMIN_EMAIL") ~
  getAliased[Option[DateTime]]("ADMIN_FIRST_PAYMENT_DATE") ~
  getAliased[Option[String]]("utm_source") ~
  getAliased[Option[String]]("utm_medium") ~
  getAliased[Option[String]]("utm_campaign") ~
  getAliased[Option[String]]("sf_exec") ~
  get[Option[Long]]("syndication_access_manager") ~
  get[Option[String]]("vat_number") ~
  get[Boolean]("bounced_email") ~
  getAliased[Option[String]]("ADMIN_COMPANY") map {
  case testUsersId ~ userEmail ~ testUsersFirstName ~ testUsersSecondName
    ~ company ~ useAs ~ stripeCustomerId ~ isInvoiceCustomer ~ xeroContactEmail ~ passwordHash ~ salt ~
    invoiceAddress ~ timeZone ~ lastPaymentDate ~ signUpDate ~ testRole ~ numTeam ~ paidForTeam ~ testUsersAdminId ~ adminLastPaymentDate ~ adminTestRole ~ firstPaymentDate ~
    adminEmail ~ adminFirstPaymentDate ~ utmSource ~ utmMedium ~ utmCampaign ~ sfExec ~ syndicationAccessManagerId ~ vatNumber ~ bouncedEmail ~ adminCompany =>
    TestUser(testUsersId, userEmail, testUsersFirstName,
      testUsersSecondName, company, useAs, invoiceAddress,
      stripeCustomerId,
      isInvoiceCustomer,
      xeroContactEmail,
      passwordHash.toVector, salt.toVector,
      teamLastPaymentDate(lastPaymentDate, adminLastPaymentDate, testUsersAdminId, stripeCustomerId), new DateTime(signUpDate, DateTimeZone.UTC),
      testRoleFromTeam(testRole, testUsersAdminId, stripeCustomerId, adminTestRole), paidByOtherUser(testUsersAdminId, stripeCustomerId), numTeam.getOrElse[Int](0), //
      getSeatCount(paidForTeam), timeZone.flatMap(getSafeTimeZone),
      firstPaymentDateFromTeam(testUsersAdminId, stripeCustomerId, firstPaymentDate, adminFirstPaymentDate), adminEmail, utmSource, utmMedium, utmCampaign,
      sfExec, syndicationAccessManagerId, vatNumber, getCompanyCustomer(testUsersAdminId, adminCompany, adminFirstPaymentDate, adminTestRole, testUsersId, company, firstPaymentDate, testRole), bouncedEmail)
}
  }

   def createCompanyCustomer(testUsersAdminId: Option[Long], adminCompany: Option[String], adminFirstPaymentDate: Option[DateTime], adminTestRole: Option[String]): Option[NewsWhipCustomer] = {
for {
  id <- testUsersAdminId
  company <- adminCompany
  firstPaymentDate <- adminFirstPaymentDate
  testRole <- adminTestRole
} yield NewsWhipCustomer(id, company, firstPaymentDate, testRole)
}

def getCompanyCustomer(testUsersAdminId: Option[Long], adminCompany: Option[String], adminFirstPaymentDate: Option[DateTime], adminTestRole: Option[String], testUserId: Long, company: String, firstPaymentDate: Option[DateTime], testRole: Option[String]): Option[NewsWhipCustomer] = {
if (testUsersAdminId.isDefined) {
  createCompanyCustomer(testUsersAdminId, adminCompany, adminFirstPaymentDate, adminTestRole)
} else {
  createCompanyCustomer(Some(testUserId), Some(company), firstPaymentDate, testRole)
}
}


def findByUserId(userId: Long): TestUser = {
DB.withConnection { implicit connection =>
  SQL"""
      SELECT s.test_users_id, s.test_users_email AS USER_EMAIL, s.test_users_first_name, s.test_users_second_name, s.company AS USER_COMPANY, s.useas, s.Stripe_CUSTOMER_ID,
  s.is_invoice_customer, s.test_users_invoice_email,
  s.password_hash, s.salt, s.invoice_address,
        s.time_zone, s.last_payment_date AS USER_LAST_PAYMENT_DATE, s.sign_up_date, s.test_role AS USER_SPIKE_ROLE, s.num_team, (SELECT COUNT(*) FROM test_users_paid_for WHERE test_users_admin_id = $userId) AS paid_for_team,
  s.syndication_access_manager, p.test_users_admin_id, pe.last_payment_date AS ADMIN_LAST_PAYMENT_DATE, pe.test_role AS ADMIN_SPIKE_ROLE,
  s.FIRST_PAYMENT_DATE AS FIRST_PAYMENT_DATE, pe.FIRST_PAYMENT_DATE AS ADMIN_FIRST_PAYMENT_DATE, pe.test_users_email AS ADMIN_EMAIL, s.utm_source, s.utm_medium, s.utm_campaign, s.sf_exec, s.bounced_email,
  s.vat_number, pe.company AS ADMIN_COMPANY

  FROM test_users AS s
  LEFT JOIN test_users_paid_for AS p ON email_users_email = s.test_users_email
  LEFT JOIN test_users AS pe ON p.test_users_admin_id = pe.test_users_id

    WHERE s.test_users_id = $userId
      """.as(simple.single)
}
}