与BIT列的LINQ联合导致指定的强制转换无效错误

时间:2011-03-08 06:38:36

标签: c# asp.net linq sql-server-2008 .net-4.0

我在几个表之间有一个复杂的连接,但我设法使用linqpad和下面的小表复制错误。 COLNAME列和YAXIS列之间以及未明确定义的COLNAME和XAXIS之间存在引用。

错误是“指定的强制转换无效”,最初我浪费时间认为问题是将数据转换回VS 2010中的对象,但错误也发生在没有定义对象的linqpad中。有点列会引起这个问题似乎很疯狂。如果我将列类型更改为VARCHAR它可以正常工作。如果我从linqpad或sql profiler运行生成的SQL也返回正常。

发生了什么事?

CREATE TABLE TEST_QUERY 
([ID] INT IDENTITY(1,1) PRIMARY KEY,
 blah VARCHAR(20))

CREATE TABLE TEST_QUERY_COLS
(QUERYID INT NOT NULL,
 COLNAME VARCHAR(20) NOT NULL,
 otherblah VARCHAR(20),
 PRIMARY KEY(QUERYID,COLNAME))

CREATE TABLE TEST_CHART
(CHARTID INT IDENTITY(1,1) PRIMARY KEY,
 QUERYID INT NOT NULL REFERENCES TEST_QUERY([ID]),
 XAXIS VARCHAR(20) NOT NULL,
 blahblah VARCHAR(20))

CREATE TABLE TEST_CHART_SERIES
(CHARTID INT NOT NULL REFERENCES TEST_CHART(CHARTID),
 YAXIS VARCHAR(20) NOT NULL,
 blahblahblah BIT NOT NULL,
 PRIMARY KEY(CHARTID,YAXIS))

INSERT INTO TEST_QUERY(blah) VALUES('xxx')
INSERT INTO TEST_QUERY_COLS(QUERYID,COLNAME,otherblah) VALUES(1,'col1','xxx')
INSERT INTO TEST_QUERY_COLS(QUERYID,COLNAME,otherblah) VALUES(1,'col2','yyy')
INSERT INTO TEST_CHART(QUERYID,XAXIS,blahblah) VALUES(1,'col1','xxx')
INSERT INTO TEST_CHART_SERIES(CHARTID,YAXIS,blahblahblah) VALUES(1,'col2',1)

这是linq声明:

((from ch in TEST_CHARTs
join a in TEST_CHART_SERIES on ch.CHARTID equals a.CHARTID into a_join
from cs in a_join.DefaultIfEmpty()
join ycols in TEST_QUERY_COLS on new { key1 = cs.YAXIS, key2 = ch.QUERYID } equals new { key1 = ycols.COLNAME, key2 = ycols.QUERYID }
where ch.CHARTID == 1
select new 
{
    ch.CHARTID,
    POSITION = 0,
    ycols.QUERYID,
    ycols.Otherblah,
    cs.Blahblahblah
})
.Union(from ch in TEST_CHARTs
join xcol in TEST_QUERY_COLS on new { key1 = ch.XAXIS, key2 = ch.QUERYID } equals new { key1 = xcol.COLNAME, key2 = xcol.QUERYID }
where ch.CHARTID == 1
select new 
{
    ch.CHARTID,
    POSITION = 0,
    xcol.QUERYID,
    xcol.Otherblah,
    Blahblahblah = false
})).Distinct()

修改:我已向微软提交了一个错误here

1 个答案:

答案 0 :(得分:3)

生成的sql包含以下行,其中@ p4对应于投影中的Blahblahblah=false行:

DECLARE @p4 Int = 0

从查询返回的int无法转换为bool。我不知道这是否是一个linq to sql bug(看起来像它),但有一个解决方法。基本上你需要从预测的匿名类型中删除Blahblahblah=false,然后从结果.ToList().ToArray()中删除,最后将linq中的bool字段添加到对象投影中:

var one =
    (from ch in TEST_CHARTs
    join a in TEST_CHART_SERIES on ch.CHARTID equals a.CHARTID into a_join
    from cs in a_join.DefaultIfEmpty()
    join ycols in TEST_QUERY_COLS on new { key1 = cs.YAXIS, key2 = ch.QUERYID } equals new { key1 = ycols.COLNAME, key2 = ycols.QUERYID }
    where ch.CHARTID == 1
    select new 
    {
        ch.CHARTID,
        POSITION = 0,
        ycols.QUERYID,
        ycols.Otherblah,
        Blahblahblah = cs.Blahblahblah
    }).ToList();

var two =
    (from ch in TEST_CHARTs
    join xcol in TEST_QUERY_COLS on new { key1 = ch.XAXIS, key2 = ch.QUERYID } equals new { key1 = xcol.COLNAME, key2 = xcol.QUERYID }
    where ch.CHARTID == 1
    select new 
    {
        ch.CHARTID,
        POSITION = 0,
        xcol.QUERYID,
        xcol.Otherblah
    }).ToList();

var three = 
    from x in two
    select new
    {
        x.CHARTID,
        x.POSITION,
        x.QUERYID,
        x.Otherblah,
        Blahblahblah = false
    };

var four = one.Union(three).Distinct();

请注意,这导致两个sql查询,而不是一个。

修改

此外,可以省略Distinct(),因为union不包含重复项。我应该读取我复制和粘贴的代码!