Linq To SQL指定的强制转换与Union无效

时间:2011-11-02 15:14:34

标签: c# linq-to-sql

我有以下代码在SQL 4.0 2008 R2服务器上再次使用.NET 4.0中的Linq to SQL:

    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行上出现错误.cocuments.Count()有效正确并从数据库中返回正确数量的记录。我也可以获取生成的文档SQL并在SSMS中运行它,结果会正确返回。

在运行的查询中,来自dataContext.EMRPatientDailyNotes的select不返回任何记录,因为该表中没有记录患者ID为231966的记录。

在GetEMRDocuments()中,如果我在两个选择中注释掉IsDeleted = e.Deleted和IsDeleted = false,那么下面的整个代码将执行而不会出错。如果我将IsDeleted = e.Deleted更改为IsDeleted = false,则代码运行时没有错误。如果我删除整个联盟并运行 以下......

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值中存在一个转换问题。可能是因为没有从dataContext.EMRPatientDailyNotes返回的结果,它试图将空值映射到联盟的IsDeleted?我不认为这会是问题,因为如果我只是将IsDeleted = e.Deleted更改为IsDeleted = false,则没有错误。因此,似乎e.Deleted返回非bool值。但是,如果e.Deleted被定义为Linq To SQL生成的代码中的bool并且它在SQL数据库中是一个非空字段,那怎么可能呢?

3 个答案:

答案 0 :(得分:2)

我终于能够让它工作,但我不知道为什么我需要改变。以下是我将查询更改为:

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 

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

然而我不知道为什么这是必需的,因为e.Deleted在数据库中被列为bool(非null),那么e.Deleted怎么会有一个null值?我现在正在将此标记为答案,但是如果有人能告诉我为什么需要更改代码或者如何在没有代码更改的情况下通过,我会将其标记为答案。

谢谢, 丹

答案 1 :(得分:0)

我在下面的函数中遇到了类似的问题。它可以在dev中完美地工作,但在生产中,在相同版本的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;
    }

然后它起作用了......去看看。

答案 2 :(得分: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
        }
    );