Обновить объект в Entity Framework - PullRequest
1 голос
/ 24 февраля 2011
public class SqlDataContext : DbContext
    {
        public DbSet<Message> Messages { get; set; }

        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
        {

            base.OnModelCreating(modelBuilder);
        }
    }

и класс хранилища:

 public class SqlRepository : IRepository
        {
            private SqlDataContext _dataContext;
            public SqlRepository(SqlDataContext dataContext) {
                _dataContext = dataContext;
            }

            public DbSet<Message> Messages {
                get { return _dataContext.Messages; } 
            }

            public void Commit() {
                _dataContext.SaveChanges();
            }

        }

и класс обслуживания:

public class MessagesServices : IMessagesServices
    {
        #region Repository        
        private IRepository _repository;
        public UsersServices(IRepository repository) {
            _repository = repository;
        }
        #endregion


        /// <summary>
    /// Update the Message in Repository
    /// </summary>
    public void Update(Message message) {
        if (message != null) {
            _repository.Messages.Attach(message);
            _repository.Commit();
        }
    }
}

Если я получу какое-либо сообщение, подобное этому:

public ViewResult Edit(int messageId)
    {
        var message = _repository.Messages.First(j => j.MessageId == messageId);
        message.Text = "Test";
        _userService.Update(message);
    }

Все будет хорошо, но изменения не сохраняются в базе данных.

Конструктор контроллера сообщений

private IRepository _repository;
        private IMessagesServices _messageServices;
        public MessagesController(IRepository repository, IMessagesServices messageServices)
        {
            _repository = repository;
            _messageServices = messageServices;
        }

хранилище, сервис и контекст данных внедряются структурной картой:

/// <summary>
        /// Configuration registry modules for DI
        /// </summary>
        public class WebUiRegistry : Registry
        {
            public WebUiRegistry()
            {
                For<DbContext>().Use(() => new SqlDataContext());      
                For<IRepository>().HttpContextScoped().Use<SqlRepository>();
                For<IUsersServices>().Use<UsersServices>();
                For<IMessagesServices>().Use<MessagesServices>();
                For<IJobAdvertsServices>().Use<JobAdvertsServices>();
                For<ILog>().Use<SqlLogServices>();
            }
        }

@ slauma Вы имеете право.

Если я попробую это:

ObjectFactory.GetInstance<SqlDataContext>().Messages.Attach(message);
                ObjectFactory.GetInstance<SqlDataContext>().Entry(message).State = EntityState.Modified;
                ObjectFactory.GetInstance<SqlDataContext>().SaveChanges();

Они все отлично работают, поэтому у меня есть несколько экземпляров SqlDataContext.

Но это:

For<SqlDataContext>().Use(() => new SqlDataContext());

не помогает. Есть идеи?

Я думаю, проблема здесь

private IRepository _repository;
        private IMessagesServices _messageServices;
        public MessagesController(IRepository repository, IMessagesServices messageServices)
        {
            _repository = repository;
            _messageServices = messageServices;
        }

Поскольку репозиторий здесь внедряется (внутри репозитория внедряется SqlDataContext) и в тот же момент внедряются сервисы (внутри внедренного репозитория, в репозитории SqlDataContext)

public class MessageController : Controller
    {
        private IRepository _repository;
        private IMessagesServices _messagesServices;
        public MessageController(IRepository repository, IMessagesServices messagesServices)
        {
            _repository = repository;
            _messagesServices = messagesServices;

            bool sameDataContexts = object.ReferenceEquals(((SqlRepository)_repository)._dataContext, ((SqlRepository)((MessagesServices)_messagesServices)._repository)._dataContext);

        }

результат равен TRUE.

РАБОЧЕЕ РЕШЕНИЕ:

private IRepository _repository;
        private IMessagesServices _messageServices;
        public MessagesController(IRepository repository)
        {
            _repository = repository;
            _messageServices = ObjectFactory.GetInstance<IUsersServices>();
        }

и в классе услуг:

/// <summary>
    /// Update the Message in Repository
    /// </summary>
    public void Update(Message message) {
        if (message != null) {
            _repository.Messages.Attach(message);
            ObjectFactory.GetInstance<SqlDataContext>().Entry(message).State = EntityState.Modified;
            _repository.Commit();
        }

Но есть ли здесь какое-нибудь решение для двух параметров конструктора? И без использования

ObjectFactory.GetInstance<SqlDataContext>().Entry(message).State = EntityState.Modified;

1 Ответ

1 голос
/ 24 февраля 2011

Попробуйте заменить эту строку ...

For<DbContext>().Use(() => new SqlDataContext());

... по

For<SqlDataContext>().Use(() => new SqlDataContext());

(или добавьте эту строку, если вам также необходимо разрешить DbContext в другом месте)

Ваш SqlRepository хочет иметь SqlDataContext в качестве параметра конструктора, а не DbContext. Так что это может быть случай, когда ваш DI-контейнер создает два новых экземпляра SqlDataContext, когда IRepository разрешается и когда IMessagesServices разрешается, вместо использования зарегистрированного экземпляра SqlDataContext. Тогда ваш репозиторий и ваш класс обслуживания будут работать с двумя разными контекстами данных, что приведет к сбою обновления.

Это всего лишь предположение, я не знаю деталей StructureMap. Но с Unity (я более знаком с этим) это не сработает: Unity не внедряет экземпляры зарегистрированного базового класса в местах, где требуется производный класс. Вам нужно зарегистрироваться для того типа класса, который вы хотите добавить.

Edit: Было бы неплохо проверить, действительно ли DataContexts, введенные в Репозиторий и в Сервис, действительно одинаковы, например, в вашем методе Контроллера Edit:

bool sameDataContexts = object.ReferenceEquals(_repository._dataContext,
    _messageServices._repository._dataContext);

(временно создайте _dataContext в репозитории и _repository в классе Service public для этого теста.)

Таким образом, мы можем четко различить, есть ли у вас проблема с инъекцией или EF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...