无法识别Anorm中的Mysql别名表

时间:2015-08-18 01:48:34

标签: scala anorm playframework-2.4

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

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
  • Anorm 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        
    } 

如果我使用attempt_1,我会收到此错误,如您所建议的那样,该错误不起作用。

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

如果我使用attempt_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

1 个答案:

答案 0 :(得分:0)

我没有在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 *)
  }
}