开发者

LINQ union with BIT column causing Specified cast is not valid error

开发者 https://www.devze.com 2023-02-15 22:50 出处:网络
I have a complicated join between a few tables but I have managed to replicate the error using linqpad and the small tables开发者_运维百科 below. There are references between the COLNAME column and th

I have a complicated join between a few tables but I have managed to replicate the error using linqpad and the small tables开发者_运维百科 below. There are references between the COLNAME column and the YAXIS column and also between COLNAME and XAXIS that is not explicitly defined.

The error is "Specified cast is not valid", which originally I wasted time thinking the problem was converting the data returned to my object in VS 2010, but the error also happens in linqpad with no defined object. It seems insane that a bit column would cause this problem. If I change the column type to a VARCHAR it works fine. If I run the generated SQL from linqpad or sql profiler that also returns fine.

What is going on?

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)

This is the linq statement:

((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()

Edit: I've filed a bug with microsoft here


The generated sql includes the following line, where @p4 corresponds to the Blahblahblah=false line in your projection:

DECLARE @p4 Int = 0

And the int that is returned from the query can't be converted to a bool. I don't know whether or not this is a linq to sql bug (seems like it), but there is a workaround. Basically you need to drop the Blahblahblah=false from the anonymous type projected, then .ToList() or .ToArray() the result, and finally add the bool field in a linq to objects projection:

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();

Note that this results in two sql queries, not one.

EDIT

Also, Distinct() can be left out, since union doesn't include duplicates. I should have actually read the code that I copied and pasted!

0

精彩评论

暂无评论...
验证码 换一张
取 消