实体框架中的更新对象

时间:2011-02-24 09:15:27

标签: asp.net-mvc entity-framework entity-framework-4 asp.net-mvc-3

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 个答案:

答案 0 :(得分:1)

尝试替换此行......

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

...通过

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

(如果您还需要在其他地方解析DbContext,请添加此行)

您的SqlRepository想要SqlDataContext作为构造函数参数,而不是DbContext。因此,当SqlDataContext被解析并且IRepository被解析时,您的DI容器会创建IMessagesServices的两个新实例,而不是使用已注册的SqlDataContext实例。您的存储库和服务类将使用两个不同的数据上下文,这将导致更新失败。

这只是猜测,我不知道StructureMap的细节。但是使用Unity(我更熟悉),这是行不通的:Unity不会在需要派生类的地方注入已注册基类的实例。您需要注册要注入的确切类类型。

修改 检查注入存储库和服务的DataContexts是否真的相同是个好主意,例如在Controller的Edit方法中:

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

(暂时为该测试在服务器类public中的存储库和_repository中创建_dataContext。)

通过这种方式,我们可以清楚地区分您是否存在注射问题或EF问题。