LINQ to SQL - Определение наличия устаревших данных - PullRequest
4 голосов
/ 04 августа 2010

Я извлекаю данные расписания из базы данных через LINQ to SQL и, следовательно, использую объект DataContext.Данные определяют, когда определенные действия должны быть выполнены, и могут быть обновлены независимо от моей службы.

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

  • Нужно ли создавать новый DataContext при каждой проверке
  • Нужно ли реализовывать пользовательскиеметод равенства для типа Row и итерации по таблицам?

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

Ответы [ 4 ]

2 голосов
/ 04 августа 2010

Хороший вопрос!

Я нашел эту запись в блоге по этому вопросу, где кто-то хотел использовать SqlDependency с LINQ to SQL ...

http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/05/04/9302.aspx

, что будет идти рука об руку с это для WinForms. (Вы не указали WinForms или ASP.NET)

Редактировать - добавлено

Обратите внимание, что это применимо только к клиентским приложениям (WinForms и т. Д.), Где имеется очень небольшое количество клиентов, или к приложению ASP.NET. Документация MSDN утверждает это в их документации в http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx:

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

Однако, если вы разрабатываете приложение только с несколькими пользователями, это должно быть приемлемо.

0 голосов
/ 04 августа 2010

Во-первых, вам нужно очень четко определить, какие данные (таблица, столбец (столбцы)) в точности подлежат вашему наблюдению за изменениями / обновлениями и что именно происходит на стороне БД при изменении этих данных.Что означает «расписание обновлено» в вашем случае - один столбец в одной строке изменяется, но это не влияет на расстановку приоритетов или столбец, который влияет на изменения приотитизации?У вас есть четкое разделение между данными, которые влияют на планирование, и данными, которые влияют только на обработку.

Ответы на эти вопросы критически определяют, что выполнимо даже в принципе.Не существует абстрактного решения проблемы планирования в целом.

Как только вы определяете, что и что влияет на что и что, и отделяете данные для реального планирования (определение, когда что-то обрабатывается) от даты обработки (определяется, как что-то обрабатывается)Вы уменьшите свою проблему до двух точек изменения и двух точек реакции.

Затем вы можете управлять вставкой и обновлением на стороне БД с помощью sprocs и триггеров, чтобы все новые вещи отмечались как таковые.Затем вы создаете sproc, который запрашивает только рыночные строки и помечает их как «прочитанные».Когда ваш средний уровень получает их, он вызывает другого sproc для подтверждения, и этот sproc помечает их как старых.Вариации этого зависят от реальной архитектуры, но это ключевой момент - , помечающий и обновляющий состояние данных на месте, то есть в SQL .SQL также потребуется триггер для возврата записей из «чтения» в «новые», если нет своевременного подтверждения (это означает, что ваш промежуточный уровень умер).

Ничего подобного с LINQ of DC вообще. Как только вы решите эту проблему, вы действительно сможете сделать эквивалент одного запроса и получать только те элементы, которые являются новыми относительно предыдущего считывания.

Кроме того, то, что вы получаете от LINQ, не являетсяссылка на таблицу в любой форме - это представление полученных записей - они будут выглядеть как записи таблицы, только если в вашем запросе не указаны поля, которые вам действительно нужны.Когда вы начнете использовать sporcs, он будет представлять собой любой результирующий набор sproc - который может быть объединением из 5 таблиц, но выбирая всего 3 поля.

0 голосов
/ 04 августа 2010

У меня есть другой ответ, который отличается от моего первого, но я все еще думаю, что первый вариант является допустимым в ограниченных ситуациях, поэтому я публикую это отдельно.обрабатывает проблемы параллелизма с LINQ.Microsoft предоставляет руководство по этому вопросу здесь:

http://msdn.microsoft.com/en-us/library/bb399373.aspx

0 голосов
/ 04 августа 2010

Автоматически сгенерированные классы, производные от DataContext, не предназначены для долгоживущих объектов. В подавляющем большинстве сценариев использования вы должны создать его экземпляр, прочитать нужные данные и / или внести необходимые изменения, отправить, а затем забыть об объекте. Он напрямую не представляет соединение с базой данных - создание экземпляров множества DataContext s не обязательно открывает несколько соединений с БД.

Следствием этого является то, что вы должны считать свои данные всегда устаревшими, особенно если отдельный процесс может получить доступ к той же базе данных. Как только вы извлечете данные, другой процесс может немедленно обновить эти данные. Единственный способ гарантировать нестабильность - это поддерживать открытую транзакцию , и, как я уверен, вы знаете, последствия сохранения транзакции открытой слишком долго - это то, что другой процесс найдет базу данных для быть крайне не отвечающим, как если бы он был очень медленным - поэтому используйте транзакцию только для шага обработки, который включает в себя только доступ к БД, который должен быть атомарным.

Таким образом, в вашем конкретном случае единственный способ выяснить, есть ли какие-либо новые действия, которые нужно выполнить, это продолжать запрашивать базу данных. Вам не нужно постоянно извлекать данные и сравнивать их с помощью Equals; Вы можете просто получить все данные, которые еще не получили, то есть указать базе данных, чтобы она возвращала только новые строки. Так как я не знаю схему вашей базы данных, я все здесь придумываю, но уверен, что это даст вам представление:

var newActions = db.ScheduledActions.Where(act => !oldActions.Contains(act)).ToList();
if (newActions.Any()) {
    // ... do something intelligent with the new actions ...
    oldActions = oldActions.Concat(newActions);
    // or perhaps oldActions.AddRange(newActions); if oldActions is a List<>
}

Редактировать: Теперь я понимаю, что вам нужно проверять не только новые действия, но также и изменения на существующие действия. Лично я бы реализовал это, используя поле даты / времени в таблице ScheduledActions, которое указывает время последнего изменения. Тогда вам не нужен специальный компаратор равенства, но вместо этого вы можете использовать его, чтобы узнать, что изменилось. К сожалению, это означает, что вам нужно получить все действия, даже те, которые не изменились. В следующем примере я предполагаю, что ScheduledActions идентифицируются первичным ключом типа string; замените его на int, если вы используете цифровые клавиши:

Dictionary<string, ScheduledAction> oldActions = new ...;

[...]

var allActions = db.Actions.ToList();
var changedActions = allActions.Where(act => !oldActions.ContainsKey(act.Id) || oldActions[act.Id].LastChanged < act.LastChanged).ToList();
if (changedActions.Any())
{
    // do something intelligent here
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...