InSingletonScope с использованием Ninject и службы Windows - PullRequest
1 голос
/ 09 февраля 2012

Я снова опубликовал этот вопрос, так как считаю его немного расплывчатым. Новое сообщение

В настоящее время я использую службу Windows с таймером 2 минуты.Сначала я использую код EF с шаблоном хранилища для доступа к данным.Я использую Ninject, чтобы ввести свои зависимости.В моем классе NinjectDependencyResolver есть следующие привязки:

ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["Database"];

Bind<IDatabaseFactory>().To<DatabaseFactory>()
                        .InSingletonScope()
                        .WithConstructorArgument("connectionString", connectionStringSettings.Name);

Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();
Bind<IMyRepository>().To<MyRepository>().InSingletonScope();

Когда моя служба запускается каждые 2 минуты, я делаю что-то похожее на это:

foreach (var row in rows)
{
    var existing = myRepository.GetById(row.Id);

    if (existing == null)
    {
        existing = new Row();

        myRepository.Add(existing);

        unitOfWork.Commit();
    }
}

Я начинаю видеть ошибкув моих журналах написано:

Изменения в базе данных были успешно приняты, но произошла ошибка при обновлении контекста объекта.ObjectContext может быть в несовместимом состоянии.Внутреннее сообщение об исключении: AcceptChanges не может продолжаться, потому что значения ключа объекта конфликтуют с другим объектом в ObjectStateManager.Перед вызовом AcceptChanges убедитесь, что значения ключей уникальны.

Правильно ли использовать InSingeltonScope при использовании Ninject в службе Windows?Я полагаю, что я пытался использовать разные области, такие как InTransientScope, но я мог только заставить InSingeltonScope работать с доступом к данным.Сообщение об ошибке имеет какое-либо отношение к Scope или не связано?

Ответы [ 2 ]

3 голосов
/ 09 февраля 2012

Предполагая, что служба - не единственный процесс, работающий с базой данных, вы не должны использовать Singleton.В этом случае происходит повторное использование DBContext с кэшированными сущностями, которые устарели.

Лучший способ - обрабатывать каждое выполнение службы по таймеру аналогично, как это делается в сетиЗапрос wcf и создайте новый обработчик заданий для запроса.

var processor = factory.CreateRowsProcessor();
processor.ProcessRows(rows);

public class RowsProcessor
{
    public Processor(UoW uow, ....)
    {
        ...
    }

    public void ProcessRows(Rows[] rows)
    {
        foreach (var row in rows)
        {
            var existing = myRepository.GetById(row.Id);

            if (existing == null)
            {
                existing = new Row();
                myRepository.Add(existing);

                unitOfWork.Commit();
            }
        }
    }
}

В зависимости от проблемы может быть даже лучше вывести цикл наружу и установить новый процессор для каждой отдельной строки.Прочитайте http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/ для получения дополнительной информации о фабриках.Также взгляните на InCallScope именованного расширения области, если вам нужно внедрить UoW в несколько классов.http://www.planetgeek.ch/2010/12/08/how-to-use-the-additional-ninject-scopes-of-namedscope/

2 голосов
/ 09 февраля 2012

InSingletonScope создаст одноэлементный контекст = один контекст на весь срок службы вашего сервиса.Это очень плохое решение .Поскольку контекст содержит все объекты из всех предыдущих событий времени, его потребление памяти возрастает, и есть возможность получать ошибки, как те, которые вы получаете в данный момент (но ошибка действительно может быть не связана с вашим одноэлементным контекстом, но, скорее всего, это не так).Исключение говорит, что у вас есть два разных объекта с одним и тем же идентификатором ключа, отслеживаемым контекстом - это недопустимо.

Вместо синглтон-ов, хранилище и контекст используют синглтон-фабрику и каждый раз даже запрашивают новые свежие экземпляры с фабрики.Удалите контекст в конце обработки временных событий.

...