Имеем алгоритм, который использует набор правил, который хранится в таблице MS SQL Server. Если переданные на вход параметры a,b,c совпали с хранящимися в таблице - будь добр, верни то, что хранится в поле d таблицы. Это для простоты, реально в базе в таблице RulesTree лежит отображение весьма раскидистого дерева правил, и каждый раз рекурсивно строить это дерево нет никакого желания - лишние запросы к БД, лишние расчеты et cetera. По грубым оценкам, с построением дерева алгоритм работает 5 секунд, без построения - 1 секунду, и это не на самой слабой системе.
Алгоритм реализуем в форме WCF-сервиса ValidationSerice. В static constructor сервиса вызываем метод pubic void RefreshCliassifiers(), который строит дерево правил, и сохраняет его в static List
Вопросов два:
1. Нужно ли вообще в данном случае хранить дерево как static List
Обновление: Попробовал через SqlDependency. Подготовил БД:
ALTER DATABASE [testbase] SET ENABLE_BROKER with rollback immediate;;
CREATE QUEUE CntQueue;
CREATE SERVICE CntChangeNotifications
ON QUEUE CntQueue
([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]);
Проверяю следующим кодом и ловлю run-time exception: Если SqlDependency используется без указания значения для Оptions, то перед выполнением команды, добавленной в экземпляр SqlDependency, необходимо вызвать метод SqlDependency.Start()
private static void Main(string[] args)
{
var connString = "Server=(local);Database=testbase;User Id=developeruser;Password=developerpassword;";
SqlDependency.Stop(connString, "CntQueue");
var sqlCommand = new SqlCommand
{
CommandText = "select * from cnt",
Notification = null,
Connection = new SqlConnection(connString)
};
SqlDependency dependency = new SqlDependency(sqlCommand);
sqlCommand.Connection.Open();
SqlDependency.Start(connString, "CntQueue");
dependency.OnChange += OnChange;
sqlCommand.ExecuteReader(); //!!!Exception!!!
while (!changed)
{
}
Console.WriteLine("Changed!");
Console.ReadKey();
SqlDependency.Stop(connString, "CntQueue");
}
private static bool changed = false;
private static void OnChange(object sender, SqlNotificationEventArgs e)
{
changed = true;
}
Но я же вызываю SqlDependency.Start()? Чего-то еще не хватает?
exception.ToString():
System.InvalidOperationException: Если SqlDependency используется без указания значения для Оptions, то перед выполнением команды, добавленной в экземпляр SqlDependency, необходимо вызвать метод SqlDependency.Start().
в System.Data.SqlClient.SqlDependency.GetDefaultComposedOptions(String server, String failoverServer, IdentityUserNamePair identityUser, String database)
в System.Data.SqlClient.SqlCommand.CheckNotificationStateAndAutoEnlist()
в System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
в System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
в System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
в System.Data.SqlClient.SqlCommand.ExecuteReader()
в ConsoleApplication1.Program.Main(String[] args) в c:\csharp\projects\ConsoleApplication1\ConsoleApplication1\Program.cs:строка 33
UPD2. Заработал в итоге такой вариант:
SqlDependency dependency = new SqlDependency(sqlCommand, "Service=CntChangeNotifications;", 31557600);
Ответ
Следующая стратегия должна подойти:
Прочитать и закешировать в памяти дерево
Подписаться на изменения таблиц при помощи SqlDependency
При приходе нотификации инвалидировать кэш и перестроить его при следующем запросе к дереву.
Комментариев нет:
Отправить комментарий