简体   繁体   中英

Linq To SQL Specified cast is not valid error with Union

I have the following code which is using Linq to SQL in .NET 4.0 agains a SQL Server 2008 R2 server:

    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;
    }

The start of the app calls Patients(); I receive a "Object reference not set to an instance of an object" "Specified cast is not valid" error on the foreach line in Patients() the first time in. The documents.Count() works correctly and returns the correct number of records from the database. I can also take the generated SQL of documents and run it in SSMS and the results return correctly.

In the query that runs, the select, from dataContext.EMRPatientDailyNotes, returns no records, because there is no record in that table for the PatientId of 231966.

In GetEMRDocuments(), if I comment out the IsDeleted = e.Deleted and IsDeleted = false in both selects, then the entire code below will execute without error. If I change IsDeleted = e.Deleted to IsDeleted = false, then the code runs without error. If I remove the entire Union and just run the following...

retVal = (from e in dataContext.EMREvaluations
          select new EMRDocument
          {
              PatientId = e.PatientId,
              IsDeleted = e.Deleted,
          });

...then this code executes without error. Also, e.Deleted is a bool from the database and not a bool?(nullable bool) and IsDeleted is a bool. Has anyone seen this type of issue before? I have no idea what to do to fix this. Also, I was previously using Linq To Entities with this same query and did not receive this error. Any help would be greatly appreciated.

Thanks, Dan

EDIT: Here's the stack trace. I had some other code that seemed to be hiding the actual error:

[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

So, apparently there's a casting issue into the bool value of IsDeleted. Could it be that it's trying to map a null value into the IsDeleted of the Union since there are no results returned from dataContext.EMRPatientDailyNotes? I don't think this would be the issue since if I just change IsDeleted = e.Deleted to IsDeleted = false, there is no error. So, it seems that e.Deleted is returning a non-bool value. But how would that be possible when e.Deleted is defined as a bool from the Linq To SQL generated code and it is a bit, not null field in the SQL database?

I was finally able to get this to work, however I don't know why my change was required. Here is what I changed my query to:

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, 
             }); 

I modified

IsDeleted = e.Deleted 

to

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

however I have no idea why this is needed because e.Deleted is listed as a bool (not null) in the database, so how could e.Deleted ever have a value of null? I am marking this as the answer for now, however if someone can tell me why this code change was needed or how I can get by without this code change, I will mark that as the answer.

Thanks, Dan

The accepted answer didn't work for me as I needed to keep the null values.

I found switching the order of the union solved the problem, just don't ask me why:

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

I had a similar problem in the below function. It would work perfectly in dev, but fail with the "Specified cast is not valid" in production, on same version of SQL Server.

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

DbDw() is the Linq To Sql DataContext

After a lot of headscracthing and trial and error, I modified it to this:

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

And then it worked... Go figure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM