加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何将派生变量添加到ResultSet

发布时间:2020-12-16 08:56:58 所属栏目:安全 来源:网络整理
导读:几乎所有我见过的指南/教程都只展示了如何从数据库中直接可用的列中解析值.例如,以下是一种非常常见的模式,我理解它在许多方面如何有用: case class Campaign(id: Int,campaign_mode_id: Int,name: String)class Application @Inject()(db: Database) exten
几乎所有我见过的指南/教程都只展示了如何从数据库中直接可用的列中解析值.例如,以下是一种非常常见的模式,我理解它在许多方面如何有用:

case class Campaign(id: Int,campaign_mode_id: Int,name: String)

class Application @Inject()(db: Database) extends Controller {

  val campaign = {
    get[Int]("campaign.id") ~
    get[Int]("campaign.campaign_mode_id") ~
    get[String]("campaign.name") map {
      case id ~ campaign_mode_id ~ name  => Campaign(id,campaign_mode_id,name)
    }
  }

  def index = Action {
    val data : List[Campaign] = db.withConnection { implicit connection =>
      SQL("SELECT id,name FROM campaign").as(campaign.*)
    }

    Ok(Json.toJson(data))
  }
}

它产生的结果可能如下所示:

[
    {
        id: 2324,campaign_mode_id: 13,name: "ABC"
    },{
        id: 1324,campaign_mode_id: 23,name: "ABCD"
    }   
]

现在,如果广告系列表格中有一个额外的日期字段,例如广告系列启动时引用的start_on,该怎么办?或者另一个名为num_followers的字段是一个整数,指的是关注者的数量?

并且假设我想在运行数据库查询之后和返回我的JSON之前进行一些计算.例如,我想要包含一个参考最新广告系列的started_on日期的latest_compaign_date.或者说我想要包含一个average_num_followers,它引用了所有广告系列的平均关注者数量.

我的最终结果如下:

{
    latest_compaign_date: 12 Dec 2018,average_num_followers: 123,campaigns: [
        {
            id: 2324,name: "ABC"
        },{
            id: 1324,name: "ABCD"
        }   
    ]
}

我知道,对于我给出的示例,我最好在我的数据库查询中进行这些计算,而不是在我的应用程序代码中.但是,如果我必须做一些非常复杂的事情并且想在我的应用程序代码中出于某种原因这样做呢?我应该如何修改我的ResutSetParser来实现这一点?

以下是我尝试过的几种方法:

不要使用ResultSetParser而是手动执行所有操作

case class CampaignData(newestCampaignDate: Long,newestCampaignId: Long,averageNumFollowers: Float,campaigns: Seq[Campaign])

  def aggregater(rows: Seq[Row]): CampaignData = {
    val newestCampaignDate: Long = getNewestDate(rows)
    val newestCampaignId: Long = getNewestCampaign(rows)
    val averageNumFollowers: Float = getAverageNumFollowers(rows)

    val campaigns: Seq[Campaign] = rows.map(row => {
      val rowMap: Map[String,Any] = row.asMap

      Campaign(
        rowMap("campaign.id").asInstanceOf[Int],rowMap("campaign.campaign_mode_id") match { case None => 0 case Some(value) => value.asInstanceOf[Int]},rowMap("campaign.name") match { case None => "" case Some(value) => value.asInstanceOf[String]}
      )
    })

    CampaignData(newestCampaignDate,newestCampaignId,averageNumFollowers,campaigns)
  }

  def index = Action {
    val data : Seq[Row] = db.withConnection { implicit connection =>
      SQL("SELECT id,name,started_on,num_followers FROM campaign")
    }

    Ok(Json.toJson(aggregater(data)))
  }

这种方法闻起来很糟糕,因为必须使用asInstanceOf来处理每个字段并且匹配非常繁琐且真实地感觉不安全.而且直觉上,我觉得Anorm应该有更好的东西,因为我可能不是第一个遇到这个问题的人.

将ResultSetParser与另一个函数结合使用

case class Campaign(id: Int,name: String)
case class CampaignData(newestCampaignDate: Long,campaigns: Seq[Campaign])

val campaign = {
  get[Int]("campaign.id") ~
  get[Int]("campaign.campaign_mode_id") ~
  get[Int]("campaign.num_followers") ~
  get[Long]("campaign.started_on") ~
  get[String]("campaign.name") map {
    case id ~ campaign_mode_id ~ num_followers ~ started_on ~ name  => Map(
      "id" -> id,"campaign_mode_id" -> campaign_mode_id,"num_followers" -> num_followers,"started_on" -> started_on,"name" -> name
    )
  }
}

def index = Action {
  val data : Map[String,Any] = db.withConnection { implicit connection =>
    SQL("SELECT id,num_followers FROM campaign").as(campaign.*)
  }

  Ok(Json.toJson(aggregator(data)))
}

def aggregator(data: Map[String,Any]): CampaignData = {
  val newestCampaignDate: Long = getNewestDate(data)
  val newestCampaignId: Long = getNewestCampaign(data)
  val averageNumFollowers: Float = getAverageNumFollowers(data)
  val campaigns: Seq[Campaign] = getCampaigns(data)

  CampaignData(newestCampaignDate,campaigns)
}

这种方法在我不必处理isInstanceOf的意义上更好,但是那时必须处理中间Map存在更大的问题.它使得所有的getter函数(例如getCampaigns)变得更加复杂.我觉得Anorm必须提供一些我不知道的开箱即用的东西.

解决方法

正如您在第一个代码段中发布的那样,代码如下

def index = Action {
    val data : List[Campaign] = db.withConnection { implicit connection =>
      SQL("SELECT id,name FROM campaign").as(campaign.*)
    }

    Ok(Json.toJson(data))
  }

通过Anorm提取器返回类型安全的Campaign列表.

通常,您将使用类似安全的函数预处理结果

case class CampaignAggregateData(campaigns:List[Campaign],averageNumFollowers:Int,newestCampaignId:Option[Long])

def aggregate(f:List[Campaign]):CampaignAggregatedData

def index = Action {
    val manyCampaign : List[Campaign] = db.withConnection { implicit connection =>
      SQL("SELECT id,name FROM campaign").as(campaign.*)
    }

    val aggregatedData:CampaignAggregateData = aggregate(manyCampaign)

    Ok(Json.toJson(data))
  }

如果您需要聚合由数据库引擎执行,通常在单个操作中有多个db.withConnection语句

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读