Указанное приведение Linq к SQL недопустимо ошибка с объединением

#c# #linq-to-sql

#c# #linq-to-sql

Вопрос:

У меня есть следующий код, который использует Linq для 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(); Я получаю «Ссылка на объект не установлена для экземпляра объекта»Ошибка «Указанное приведение недопустимо» в строке foreach в Patients() в первый раз. Документы.Count() работает корректно и возвращает правильное количество записей из базы данных. Я также могу взять сгенерированный SQL документов и запустить его в SSMS, и результаты вернутся правильно.

В выполняемом запросе выберите из DataContext.EMRPatientDailyNotes, не возвращает записей, потому что в этой таблице нет записи для идентификатора пациента 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 для объектов с этим же запросом и не получил эту ошибку. Любая помощь будет с благодарностью.

Спасибо, Дэн

Редактировать:Вот трассировка стека. У меня был какой-то другой код, который, казалось, скрывал фактическую ошибку:

 [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:SVNApplicationbranchesdan.cagneyATI.TherapyConnectService.asmx.cs:57
ATI.TherapyConnect.Content.UserControls.Shared.Patients.MyPatientsList.BindGrid(String inSortExpression, Int32 inCurrentPage) in C:SVNApplicationbranchesdan.cagneyATI.TherapyConnectContentUserControlsSharedPatientsMyPatientsList.ascx.cs:129
ATI.TherapyConnect.Content.UserControls.Shared.Patients.MyPatientsList.Page_Load(Object sender, EventArgs e) in C:SVNApplicationbranchesdan.cagneyATI.TherapyConnectContentUserControlsSharedPatientsMyPatientsList.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
  

Итак, по-видимому, существует проблема с приведением к значению bool IsDeleted . Может ли быть так, что он пытается сопоставить нулевое значение с IsDeleted объединения, поскольку из DataContext не возвращаются результаты.EMRPatientDailyNotes? Я не думаю, что это было бы проблемой, поскольку, если я просто изменю IsDeleted = e.Deleted на IsDeleted = false, ошибки не будет. Итак, похоже, что e.Deleted возвращает значение, отличное от bool. Но как это было бы возможно, если e.Deleted определяется как bool из сгенерированного кода Linq To SQL, и это поле bit, а не null в базе данных SQL?

Ответ №1:

Я, наконец, смог заставить это работать, однако я не знаю, зачем потребовалось мое изменение. Вот на что я изменил свой запрос:

 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. Это ошеломляет. У меня был тот же сценарий, и это также устранило мою проблему.

Ответ №2:

У меня была аналогичная проблема в приведенной ниже функции. Это отлично работало бы в dev, но сбой с «Указанное приведение недопустимо» в рабочей среде на той же версии SQL Server.

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

DbDw() — это ссылка на Sql DataContext

После долгих размышлений, проб и ошибок я изменил его на это:

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

И тогда это сработало… Поди разберись.

Ответ №3:

Принятый ответ не сработал для меня, так как мне нужно было сохранить значения null.

Я обнаружил, что переключение порядка объединения решило проблему, просто не спрашивайте меня, почему:

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