C# SQL-запрос для ретранслятора asp.

Я работаю над отчетом, который будет принимать все посещения, которые произошли в любой месяц, и отображать некоторую основную информацию. У меня есть все части, за исключением FirstName и LastName людей, которые посетили этот визит. Может быть от 0 до бесконечного количества посетителей за посещение.

Для этого есть 3 таблицы SQL. dbo.CaseNotes, dbo.VisitAttendance и dbo.Persons

Они связаны с dbo.CaseNotes[CaseNoteID] в dbo.VisitAttendance[CaseNoteID] dbo.VisitAttendance[CasePersonID] в dbo.Persons[PersonID]

От dbo.Persons я могу получить FirstName и LastName из PersonID.

Ошибка исходит от "Те, присутствующих". любая помощь будет принята с благодарностью.

Вот мой текущий код:

private void Services_BindGrid(DateTime begin, DateTime end)
    {
        using (var db = new FormsDataContext())
        {

            var caseID = Convert.ToInt32(Request.QueryString["CaseID"]);

            var _visitAttend = db.VisitAttendances.Where(v => v.CaseID == caseID);

            var query = db.CaseNotes.Where(c => c.CaseID == caseID && c.VisitDate >= begin && c.VisitDate <= end)

                         .Select(c=>new 
                {
                    VisitDate = c.VisitDate,
                    StartTime = c.StartTime,
                    EndTime = c.EndTime,
                    Duration = c.Duration,
                    TypeOfContact = db.DropDowns.SingleOrDefault(d => d.DropDownID == c.TypeOfContact).DisplayText,
                    LocationOfVisit = db.DropDowns.SingleOrDefault(d => d.DropDownID == c.LocationOfVisit).DisplayText,
                    VisitPunctuality = c.VisitPuncuality,
                    ThosePresent = db.VisitAttendances.SingleOrDefault(v => v.CaseNoteID == c.CaseNoteID).CasePersonID.ToString()
                });


            rptContacts.DataSource = query.ToList();
            rptContacts.DataBind();
        }

    }

1 ответ

Решение

Я предполагаю, что вы используете Linq2Sql из-за суффикса DataContext, Обратите внимание, что SingleOrDefault вернет ноль, если записи не найдены, и сгенерирует исключение, если будет найдено более одной записи, поэтому доступ к нему невозможен. CasePersonID без предварительной проверки на ноль.

Хотя вы могли бы сделать что-то громоздкое, как:

ThosePresent = db.VisitAttendances.SingleOrDefault(v => v.CaseNoteID == c.CaseNoteID) != null
             ? db.VisitAttendances.SingleOrDefault(v => v.CaseNoteID == c.CaseNoteID).CasePersonID.ToString()
             : "No One"

производительность будет еще хуже, чем сейчас. Обратите внимание, что в настоящее время звонки db.DropDowns.SingleOrDefault а также db.VisitAttendances.SingleOrDefault будет выполняться один раз для каждого анонимного объекта, спроецированного по вашему запросу.

Могу ли я порекомендовать вместо этого использовать комбинацию активной загрузки и навигации по внешним ключам, чтобы заставить Sql выполнить объединение в базе данных. Сделайте это, добавив это сразу после создания контекста:

 var options = new DataLoadOptions();
 options.LoadWith<CaseNotes>(x => x.VisitAttendances);
 db.LoadOptions = options;

И тогда вы можете сделать так:

 ThosePresent = c.VisitAttendances
    .SingleOrDefault(v => v.CaseNoteID == c.CaseNoteID)

(хотя, опять же, перед разыменованием вам нужно будет проверить нулевой результат). Тогда реальное решение состоит в том, чтобы использовать промежуточную проекцию, материализоваться (после фильтрации), а затем сделать окончательную проекцию в промежуточной проекции:

.Select(c => new 
{
   ...
   tmpThosePresent = c.VisitAttendances
    .SingleOrDefault(v => v.CaseNoteID == c.CaseNoteID)
   ...
}
.ToList()
.Select(c => new
{
    ...
    ThosePresent = c.tmpThosePresent != null
       ? c.tmpThosePresent.CasePersonID.ToString()
       : "No One"
    ...
});

Точно так же для выпадающих меню, если они имеют навигационные внешние ключи от объектов домена, вы также можете загрузить с LoadsWithили, в качестве альтернативы, если они constant данные, загрузить их в статический Dictionary кеш с ключом DropDownID,

Другие вопросы по тегам