Linq To SQL 中的 Union 操作出现 "指定的转换无效" 错误

3

我有以下代码,它使用Linq to SQL在.NET 4.0中与SQL Server 2008 R2服务器交互:

    public void Patients()
    {
        var documents = GetEMRDocumentsByPatientId("231966");
        if (documents.Count() > 0)
        {
            foreach (var doc in documents)
            {
                Console.WriteLine(doc.PatientId);
            }
        }
    }

    public static IQueryable<EMRDocument> GetEMRDocumentsByPatientId(string inPatientId)
    {
        return GetEMRDocuments().Where(d => String.Equals(d.PatientId, inPatientId));
    }

    public static IQueryable<EMRDocument> GetEMRDocuments()
    {
        var dataContext = InitializeDataContext();
        IQueryable<EMRDocument> retVal = null;

        retVal = (from e in dataContext.EMREvaluations
                  select new EMRDocument
                  {
                      PatientId = e.PatientId,
                      IsDeleted = e.Deleted,
                  }).Union(
                 from e2 in dataContext.EMRPatientDailyNotes
                 select new EMRDocument
                 {
                     PatientId = e2.PatientID,
                     IsDeleted = false,
                 });
        return retVal;
    }

该应用程序的启动调用了Patients()方法; 在第一次进入Patients()方法时,在foreach循环行上收到“对象引用未设置为对象实例”的错误或“指定的强制转换无效”的错误。documents.Count()函数能够正确地返回数据库中记录的正确数目。我还可以在SSMS中运行documents生成的SQL查询,结果也是正确的。
在运行的查询中,dataContext.EMRPatientDailyNotes的select和from语句没有返回任何记录,因为该表中不存在PatientId为231966的记录。
在GetEMRDocuments()方法中,如果注释掉两个select语句中的IsDeleted = e.Deleted和IsDeleted = false,则以下所有代码都会执行而不会出错。如果将IsDeleted = e.Deleted改为IsDeleted = false,则该代码也会正常运行。如果删除整个Union,只运行以下内容...
retVal = (from e in dataContext.EMREvaluations
          select new EMRDocument
          {
              PatientId = e.PatientId,
              IsDeleted = e.Deleted,
          });

如果没有错误,那么这段代码就会执行。此外,e.Deleted是来自数据库的bool类型,而不是bool?(可空bool)类型,而IsDeleted是bool类型。有人遇到过这种问题吗?我不知道该怎么解决。此外,我之前在使用相同的查询时使用了Linq To Entities,并没有收到此错误。非常感谢任何帮助。
谢谢, 丹
编辑: 以下是堆栈跟踪。我有一些其他代码似乎隐藏了实际的错误:
[InvalidCastException: Specified cast is not valid.]
System.Data.SqlClient.SqlBuffer.get_Boolean() +5057281
System.Data.SqlClient.SqlDataReader.GetBoolean(Int32 i) +38
Read_EMRDocument(ObjectMaterializer`1 ) +313
System.Data.Linq.SqlClient.ObjectReader`2.MoveNext() +32
ATI.TherapyConnect.Service.Patients() in C:\SVN\Application\branches\dan.cagney\ATI.TherapyConnect\Service.asmx.cs:57
ATI.TherapyConnect.Content.UserControls.Shared.Patients.MyPatientsList.BindGrid(String inSortExpression, Int32 inCurrentPage) in C:\SVN\Application\branches\dan.cagney\ATI.TherapyConnect\Content\UserControls\Shared\Patients\MyPatientsList.ascx.cs:129
ATI.TherapyConnect.Content.UserControls.Shared.Patients.MyPatientsList.Page_Load(Object sender, EventArgs e) in C:\SVN\Application\branches\dan.cagney\ATI.TherapyConnect\Content\UserControls\Shared\Patients\MyPatientsList.ascx.cs:68
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
System.Web.UI.Control.OnLoad(EventArgs e) +91
System.Web.UI.Control.LoadRecursive() +74
System.Web.UI.Control.LoadRecursive() +146
System.Web.UI.Control.LoadRecursive() +146
System.Web.UI.Control.LoadRecursive() +146
System.Web.UI.Control.LoadRecursive() +146
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207

显然,在IsDeleted的bool值中存在转型问题。这可能是因为它正在尝试将null值映射到Union的IsDeleted中,因为从dataContext.EMRPatientDailyNotes返回了零个结果。但我认为这不是问题,因为如果我只是将IsDeleted = e.Deleted更改为IsDeleted = false,就没有错误。所以,似乎e.Deleted返回了非bool值。但是当Linq To SQL生成的代码中将其定义为bool且它是SQL数据库中的bit(不是null字段)时,这怎么可能呢?

3个回答

3

最终我成功地让它工作了,但是我不知道为什么需要我的更改。这是我将查询更改为的内容:

retVal = (from e in dataContext.EMREvaluations 
              select new EMRDocument 
              { 
                  PatientId = e.PatientId, 
                  IsDeleted = e.Deleted == null ? false : e.Deleted, 
              }).Union( 
             from e2 in dataContext.EMRPatientDailyNotes 
             select new EMRDocument 
             { 
                 PatientId = e2.PatientID, 
                 IsDeleted = false, 
             }); 

我修改了

IsDeleted = e.Deleted 

to

IsDeleted = e.Deleted == null ? false : e.Deleted

然而我不知道为什么需要这样做,因为在数据库中,e.Deleted被列为布尔类型(非空),那么e.Deleted怎么可能有null的值呢?我暂时将此标记为答案,但如果有人能告诉我为什么需要这个代码更改或者如何避免这个代码更改,我会将其标记为答案。

谢谢, 丹


这真是令人难以置信。我也遇到了同样的情况,而这个解决方案也解决了我的问题。 - Gunner Barnes

0

对我来说,被接受的答案不起作用,因为我需要保留空值。

我发现改变联合顺序解决了问题,只是不要问我为什么:

retVal = 
    (
        from e2 in dataContext.EMRPatientDailyNotes 
        select new EMRDocument 
        { 
            PatientId = e2.PatientID, 
            IsDeleted = (bool?)false
        }
    )
    .Union(
        from e in dataContext.EMREvaluations 
        select new EMRDocument 
        { 
            PatientId = e.PatientId, 
            IsDeleted = e.Deleted
        }
    ); 

0

我在下面的函数中遇到了类似的问题。它可以在开发环境中完美运行,但在生产环境中,使用相同版本的 SQL Server 时会出现"指定的转换无效"的错误。

public IQueryable<Contract> AllContracts()
    {
        IQueryable<Contract> contracts =
            from c in DbDw().Contracts
            select c;
        return contracts;
    }

DbDw() 是 Linq To Sql 的 DataContext。

经过许多思考和试错,我将其修改为以下内容:

public IQueryable<Contract> AllContracts()
    {
         return DbDw().Contracts;
    }

然后它就工作了...想想也是。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接