Динамический запрос с linq к объектам с использованием PredicateBuilder

Я пытаюсь выполнить запрос к очень простой таблице, но не получаю никакого результата. Таблица содержит журнал действий со следующими столбцами:

  • Я БЫ
  • ActionTypeID (создание, редактирование или удаление)
  • EntryID (идентификатор созданной / отредактированной / или удаленной записи)
  • TableName (где было совершено действие)
  • ControlName
  • Лицо (совершившее действие. NT-пользователь с отделом)
  • Дата

То, что я хотел получить, это список всех EntryID с ActionTypeID == 1 и Person (отдел), заканчивающийся одной из динамического списка строк. Проблема заключается в том, что только первое действие для одного EntryID в журнале действий должно быть проверено на соответствие одному из этих отделов.

Я знаю, это звучит довольно странно. Это может быть результатом моего плохого английского и неспособности проектирования базы данных моего бывшего коллеги. Я не знаю, что хуже.

Моя попытка получить желаемый результат заключается в следующем:

var predicate = PredicateBuilder.False<ActionLog>();
var pOuter = PredicateBuilder.True<ActionLog>();

pOuter = pOuter.And(h => h.TableName.ToUpper() == "Contact".ToUpper());
pOuter = pOuter.And(h => h.ActionType.ID == 1);

foreach (var dep in b.DepartmentList)
{
    predicate = predicate.Or(x => x.Person.EndsWith("/" + dep.Value));
}

pOuter = pOuter.And(predicate.Expand());

mContactIDs = (from h in db.ActionLog
orderby h.Date
select h).AsExpandable().Where(pOuter).Select(x => x.EntryID).Distinct().ToList();

Но это возвращает мне все записи, где "Персона" заканчивается выбранными отделами. Я просто хочу проверить первую запись с этим EntryID.

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

о, кстати, это.Net 3.5

РЕДАКТИРОВАТЬ Я думаю, у меня есть некоторые проблемы с поиском правильного объяснения - я попробую его с некоторыми фиктивными данными.

ID | ActionTypeID | EntryID | TableName  | ControlName | Person             | Date
----------------------------------------------------------------------------------------
1  | 1            | 3       | 'Contacts' | NULL        | 'xxxx/department1' | 04/11/2012
2  | 1            | 3       | 'Contacts' | NULL        | 'yyyy/department2' | 04/11/2012
3  | 1            | 5       | 'Contacts' | NULL        | 'yyyy/department2' | 04/13/2012
4  | 1            | 14      | 'Contacts' | NULL        | 'zzzz/department1' | 04/16/2012

В моем примере я бы искал записи в журнале с "Лицо, оканчивающееся на" / Department2 ", создало первое вхождение нового EntryID", "TableName ==" Контакты "" и "ActionTypeID == 1". Результат, который я хочу получить, будет (только EntryIDs) 5, так как это единственная запись, в которой пользователь отдела2 был первым. Вставка этого EntryID с ActionTypeID 1. Я знаю, что это глупо, и если я спроектировал базу данных, то я Я бы так не поступил, но теперь я должен с этим справиться. Если количество отделов для запроса не будет динамическим, я бы использовал этот фрагмент:

IQueryable<ActionLog> log = db.ActionLog;
mContactIDs = (from k in db.Contacts
    where (from h in log
        where h.TableName == "Contacts"
        && h.EntryID == k.ID
        && h.ActionType.ID == 1
        orderby h.Date
        select h).FirstOrDefault().Person.EndsWith("/" + b.Department)
    select k.ID).ToList();

Но я не знаю, как связать эти динамические отделы с глупым дизайном (и несколькими ActionTypeID 1 (создать) для одной записи. Я даже не знаю, почему приложение сохраняет это)

Спасибо, Бен.

2 ответа

Решение

Я решил использовать Entity SQL вместо этого.

        List<int> mContactIDs = new List<int>();
        using (var db = new Entities())
        {
            string queryString = @"
                                SELECT  
                                    VALUE H.EntryID
                                FROM    
                                    Entities.ActionLog AS H
                                WHERE 
                                    H.ID IN (
                                        SELECT VALUE TOP (1) Hi.ID
                                        FROM Entities.ActionLog AS Hi
                                        WHERE Hi.ActionType.ID = 1
                                        AND Hi.TableName = 'Kontakt'
                                        AND Hi.EntryID = H.EntryID
                                        ORDER BY Hi.Date    
                                    )
                                {0}
                                GROUP BY H.EntryID";

            List<string> lDepartments = new List<string>();
            foreach (var dep in b.DepartmentList)
            {
                lDepartments.Add(string.Format(" H.Person LIKE '%{0}' ", dep.Value));
            }

            string sDepartmentQuery = string.Empty;
            if (lDepartments.Count > 0)
            {
                sDepartmentQuery = string.Format(" AND ({0}) ", string.Join(" OR ", lDepartments.ToArray()));
            }

            var result = db.CreateQuery<int>(string.Format(queryString, sDepartmentQuery));
            if (result != null && result.Count() > 0)
            {
                mContactIDs = result.ToList();
            }
        }

Я думаю, что проблема заключается в захваченном значении переменной (т.е. dep.Value) внутри цикла foreach. Сделайте копию переменной и используйте ее в выражении. Проблема объясняется здесь.

foreach (var dep in b.DepartmentList)
{
    var depValue = dep.Value;
    predicate = predicate.Or(x => x.Person.EndsWith("/" + depValue));
}
Другие вопросы по тегам