【问题标题】:Mysql Aliased tables in Anorm are not recognizedAnorm中的Mysql别名表无法识别
【发布时间】:2015-11-10 19:02:38
【问题描述】:

更新 为此问题创建了一个可运行的演示。

https://github.com/narayanjr/anorm_test

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~

我无法访问别名表上的字段。我不断收到错误消息,说该字段不是一个选项,可用字段是基本字段名称或“table_name”.field_name。但不是别名字段名称。这使得不可能两次加入同一个表并访问所有字段。

var vendor_client_parser_1 = SqlParser.long("vid") ~ SqlParser.str("vname") ~ SqlParser.long("cid") ~ SqlParser.str("cname") map 
{
    case vid ~ vn ~ cid ~ cn => println(vid + "," + vn + "," + cid + "," + cn + ",")
}

var vendor_client_parser_2 = SqlParser.long("v.business_id") ~ SqlParser.str("v.name") ~ SqlParser.long("c.business_id") ~ SqlParser.str("c.name") map 
{
    case vid ~ vn ~ cid ~ cn => println(vid + "," + vn + "," + cid + "," + cn + ",")
}

var vendor_client_parser_3 = SqlParser.long(1) ~ SqlParser.str(2) ~ SqlParser.long(3) ~ SqlParser.str(4) map 
{
    case vid ~ vn ~ cid ~ cn => println(vid + "," + vn + "," + cid + "," + cn + ",")
}

DB.withConnection 
{
    implicit c =>
    var results = 
    SQL"""
        SELECT v.business_id AS vid, v.name AS vname, c.business_id AS cid, c.name AS cname
        FROM #$BUSINESS_CONNECTION_TABLE
        JOIN #$BUSINESS_TABLE AS v ON (vendor_id = v.business_id)
        JOIN #$BUSINESS_TABLE AS c ON (client_id = c.business_id)
        LIMIT 20
    """.as(vendor_client_parser.*)
}

预期结果:

1,  Vendor A,   10, Vendor K
2,  Vendor B,   11, Vendor L
2,  Vendor B,   1,  Vendor A
12, Vendor M,   3,  Vendor C

来自 vendor_client_parser_1 的结果:

10, Vendor K,   10, Vendor K
11, Vendor L,   11, Vendor L
1,  Vendor A,   1,  Vendor A
3,  Vendor C,   3,  Vendor C

来自 vendor_client_parser_2 的结果:

Execution exception[[AnormException: 'v.business_id' not found, available columns: business.business_id, business_id, business.name, name, business.business_id, business_id, business.name, name]]

来自 vendor_client_parser_3 的结果:(与预期相同)

1,  Vendor A,   10, Vendor K
2,  Vendor B,   11, Vendor L
2,  Vendor B,   1,  Vendor A
12, Vendor M,   3,  Vendor C

vendor_client_parser_3 有效,但它依赖于使用索引而不是名称。我不喜欢使用索引,因为如果我弄乱了索引,我可能仍然会得到有效的响应而不会注意到。如果我弄乱了名称,该列将不存在,我会知道有问题。

我有什么遗漏吗?有什么方法可以在不依赖索引的情况下达到我需要的结果?

  • 播放 Scala 2.4.1
  • 异常 2.5.0

更新: 如果我不对列使用别名并使用vendor_client_parser_2,我会得到与列别名时相同的结果。

修改后的查询:

SQL"""
    SELECT v.business_id, v.name, c.business_id, c.name
    FROM #$BUSINESS_CONNECTION_TABLE
    JOIN #$BUSINESS_TABLE AS v ON (vendor_id = v.business_id)
    JOIN #$BUSINESS_TABLE AS c ON (client_id = c.business_id)
    LIMIT 20
""".as(vendor_client_parser_2.*)

vendor_client_parser_2.* 的结果:

Execution exception[[AnormException: 'v.business_id' not found, available columns: business.business_id, business_id, business.name, name, business.business_id, business_id, business.name, name]]

我还用一个别名表对其进行了测试,它拒绝查看别名表名

单表测试:

SQL"""
    SELECT v.business_id, v.name, business_id, name
    FROM #$BUSINESS_TABLE AS v 
    LIMIT 20
""".as(test_parser.*)

test_parser:

var test_parser = SqlParser.long("v.business_id") ~ SqlParser.str("v.name") ~ SqlParser.long("business_id") ~ SqlParser.str("name") map 
{
    case vid ~ vn ~ cid ~ cn => println(vid + "," + vn + "," + cid + "," + cn + ",")
}

结果:

[AnormException: 'v.business_id' not found, available columns: business.business_id, business_id, business.name, name, business.business_id, business_id, business.name, name]

然后我测试了别名列是否可以通过其原始名称和别名名称访问。

测试别名列:

SQL"""
    SELECT business_id AS vid, name AS vname
    FROM #$BUSINESS_TABLE 
    LIMIT 20
""".as(test_parser_2.*)

test_parser_2:

var test_parser_2 = SqlParser.long("business_id") ~ SqlParser.str("name") ~ SqlParser.long("vid") ~ SqlParser.str("vname") map 
{
    case vid ~ vn ~ cid ~ cn => println(vid + "," + vn + "," + cid + "," + cn + ",")
}

此测试没有出错,它正确地提取了 business_id 和 vid 值。以及 name 和 vname。

我强迫它出错,所以它会给我一个列名列表。看起来 Anorm 并没有提供非别名名称作为建议,但它们在这种情况下确实有效。

[AnormException: 'forceError' not found, available columns: business.business_id, vid, business.name, vname]

我也试过不使用 SqlParser。

var businesses = SQL"""
    SELECT v.business_id AS vid, v.name AS vname, c.business_id AS cid, c.name AS cname
    FROM #$BUSINESS_CONNECTION_TABLE
    JOIN #$BUSINESS_TABLE AS v ON (vendor_id = v.business_id)
    JOIN #$BUSINESS_TABLE AS c ON (client_id = c.business_id)
    LIMIT 20
""".fold(List[(Long, String, Long, String)]())
    { 
        (list, row) =>
        list :+ (row[Long]("v.business_id"), row[String]("v.name"), row[Long]("c.business_id"), row[String]("c.name")) //attempt_1    
        //list :+ (row[Long]("vid"), row[String]("vname"), row[Long]("cid"), row[String]("cname")) //attempt_2        
    } 

如果我使用尝试_1,我会收到这个错误,正如你所建议的那样,它不应该起作用。

Left('v.business_id' not found, available columns: business.business_id, vid, business.name, vname, business.business_id, cid, business.name, cname)))

如果我使用尝试_2,我会得到与 vendor_client_parser_1 相同的结果

10, Vendor K,   10, Vendor K
11, Vendor L,   11, Vendor L
1,  Vendor A,   1,  Vendor A
3,  Vendor C,   3,  Vendor C

如果我不对列设置别名并使用相同的方法

SQL"""
    SELECT v.business_id, v.name, c.business_id, c.name
    FROM #$BUSINESS_CONNECTION_TABLE
    JOIN #$BUSINESS_TABLE AS v ON (vendor_id = v.business_id)
    JOIN #$BUSINESS_TABLE AS c ON (client_id = c.business_id)
    LIMIT 20
""".fold(List[(Long, String, Long, String)]())
    { 
        (list, row) =>
        list :+ (row[Long]("v.business_id"), row[String]("v.name"), row[Long]("c.business_id"), row[String]("c.name")) //Attempt_3            
    } 

使用此查询而不给列添加别名会导致此错误,

Left('v.business_id' not found, available columns: business.business_id, business_id, business.name, name, business.business_id, business_id, business.name, name)))

然后我使用这种方法测试了一个简单的别名表

SQL"""
    SELECT v.business_id, v.name
    FROM #$BUSINESS_TABLE AS v
    LIMIT 20
""".fold(List[(Long, String)]())
    { 
        (list, row) =>
        list :+ (row[Long]("v.business_id"), row[String]("v.name")) //simple_attempt_1       
    } 

我遇到同样的错误

Left(List(java.lang.RuntimeException: Left('v.business_id' not found, available columns: business.business_id, business_id, business.name, name)))

据我所知,如果使用字段名称而不是索引两次使用同一个表,则无法访问作为别名表一部分的字段。

更新 2:

我尝试颠倒 SQL 中字段的顺序,使其为 c.business_id AS cid, c.name AS cname, v.business_id AS vid, v.name AS vname 并重新运行 vendor_client_parser_1。它给了我相反的结果

vendor_client_parser_1 的结果,mysql 字段已切换:

1,  Vendor A,   1,  Vendor A
2,  Vendor B,   2,  Vendor B
2,  Vendor B,   2,  Vendor B
12, Vendor M,   12, Vendor M

当我强制出错并显示我得到这些可能的字段时,

按原顺序排列的字段:

Left('forceError' not found, available columns: business.business_id, vid, business.name, vname, business.business_id, cid, business.name, cname)

切换顺序的字段:

Left('forceError' not found, available columns: business.business_id, cid, business.name, cname, business.business_id, vid, business.name, vname)

这让我觉得这种情况正在发生。

如果在查询结果中发现多个具有相同名称的列,例如 Country 和 CountryLanguage 表中名为 code 的列,则可能存在歧义。默认情况下,如下映射将使用最后一列:

https://www.playframework.com/documentation/2.4.1/ScalaAnorm

如果您查看建议的字段 business.business_idbusiness.name 出现两次,因为该表被引用了两次。似乎 Anorm 将最后一次出现的 business.business_idbusiness.name 与两个别名相关联。

更新 为此问题创建了一个可运行的演示。 https://github.com/narayanjr/anorm_test

【问题讨论】:

  • 一旦为列设置别名,就无法使用原始名称访问它。如果你想使用它,不要给它加上别名,或者有两次列(带 & 不带别名)。
  • @cchantep 我尝试按照您的建议进行更改。结果已添加到问题中。
  • 如果你查看错误的详细信息,你会发现列的FQDN不是用表的别名计算的,有v,而只是用原始表名。越简单越好:确保您的 SELECT 使用唯一的列或别名来投影值,并且只使用这些简单的唯一名称,这里只是 "business_id""name"
  • @cchantep 我已经尝试过了,但它似乎无法正常工作。看看vendor_client_parser_1 和我从中得到的结果。那是使用唯一的别名,但结果是错误的。 cidcname 的值同时用于 vid 和 `vname。这有什么关系吗? "如果在查询结果中发现多个具有相同名称的列,例如 Country 和 CountryLanguage 表中名为 code 的列,则可能存在歧义。默认情况下,如下所示的映射将使用最后一列 " playframework.com/documentation/2.4.1/ScalaAnorm
  • 在 Anorm 中测试了对列别名的支持。确保所有名称都是唯一的,并按照提示检查哪些名称可用(在错误详细信息中)。

标签: scala anorm playframework-2.4


【解决方案1】:

我没有在 2.4 中尝试过,但您可以使用解析器方法为您生成列名,而不是变量。我的方法如下:

case class BusinessConnection(vendor_id: Int, client_id: Int)
case class Business(id: Int, name: String)
case class VendorClient(vendor: Business, client: Business)

object VendorClient {
  val businessConnectionP =
    get[Int]("vendor_id") ~
      get[Int]("client_id") map {
        case vendor_id ~ client_id =>
          BusinessConnection(vendor_id, client_id)
      }
  def businessP(alias: String) =
    getAliased[Int](alias + ".id") ~
      getAliased[String](alias + ".name") map {
        case id ~ name =>
          Business(id, name)
      }
  val vendorClientP =
    businessP("v") ~ businessP("c") map {
      case business ~ client =>
        VendorClient(business, client)
    }
  val sqlSelector = "v.id, v.name, c.id, c.name"
  def all() = DB.withConnection { implicit c =>
    SQL(s"""
      select $sqlSelector
      from businessConnection
        join business as v on vendor_id=v.id
        join business as c on client_id=c.id
      """).as(vendorClientP *)
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-23
    • 1970-01-01
    • 2016-09-16
    • 2012-12-26
    • 2019-01-16
    • 2019-08-05
    • 2010-10-05
    • 2018-11-03
    相关资源
    最近更新 更多