#c_sharp #entity_framework
Имеем алгоритм, который использует набор правил, который хранится в таблице MS SQL Server. Если переданные на вход параметры a,b,c совпали с хранящимися в таблице - будь добр, верни то, что хранится в поле d таблицы. Это для простоты, реально в базе в таблице RulesTree лежит отображение весьма раскидистого дерева правил, и каждый раз рекурсивно строить это дерево нет никакого желания - лишние запросы к БД, лишние расчеты et cetera. По грубым оценкам, с построением дерева алгоритм работает 5 секунд, без построения - 1 секунду, и это не на самой слабой системе. Алгоритм реализуем в форме WCF-сервиса ValidationSerice. В static constructor сервиса вызываем метод pubic void RefreshCliassifiers(), который строит дерево правил, и сохраняет его в static ListrulesList. Работу с базой ведем через EF. Но правила имеют свойства меняться. Под это дело есть отдельный интерфейс, изменять который нельзя (т.е. мы не можем вызывать RefreshClassifiers или сохранять в базе итоговый набор правил в требуемом нашему алгоритму виде). Ну и классификатор, увы, не один. Меняются они редко, но меняются. Вопросов два: 1. Нужно ли вообще в данном случае хранить дерево как static List rulesList, или есть другие варианты? 2. Как выяснить, что в таблицу RulesTree внесли изменения без перестроения списка правил? Обновление: Попробовал через 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);
Ответы
Ответ 1
Следующая стратегия должна подойти: Прочитать и закешировать в памяти дерево Подписаться на изменения таблиц при помощи SqlDependency При приходе нотификации инвалидировать кэш и перестроить его при следующем запросе к дереву.
Комментариев нет:
Отправить комментарий