更新实体框架中的对象

发布于 2024-10-19 03:47:46 字数 5102 浏览 1 评论 0原文

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;
public class SqlDataContext : DbContext
    {
        public DbSet<Message> Messages { get; set; }

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

            base.OnModelCreating(modelBuilder);
        }
    }

and repository class:

 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();
            }

        }

and service class:

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();
        }
    }
}

If i get any message like this:

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

Everything will be okay, but the changes are not saved to the database.

Message Controller constructor

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

repository, service and data context are injected by stucture map:

/// <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 You have right.

If i try this:

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

Them all works fine, so i have multiple instance of SqlDataContext.

But this:

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

don't help. Any idea?

I think, problem is here

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

Because repository is here injected (inside repository is injected SqlDataContext) and in same moment is injected services (inside injected repository, in repository 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);

        }

result is TRUE.

WORKING Solution:

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

and in services class:

/// <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();
        }

But i here any solution for two constructor parameters ? And non-using

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

飞烟轻若梦 2024-10-26 03:47:46

尝试替换这一行...

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

...

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

(或者如果您还需要在其他地方解析DbContext,则添加这一行)

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

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

编辑:
最好检查注入存储库和服务的 DataContext 是否确实相同,例如在控制器的 Edit 方法中:(

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

在存储库中创建 _dataContext,在Service 类 public 暂时用于该测试。)

这样我们就可以清楚地区分您是否有注入问题或 EF 问题。

Try to replace this line ...

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

...by

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

(or add this line if you also need DbContext to be resolved somewhere else)

Your SqlRepository wants to have a SqlDataContext as constructor parameter, not a DbContext. So it could be the case the your DI container creates two new instances of the SqlDataContext when IRepository gets resolved and when IMessagesServices gets resolved, instead of using the registered SqlDataContext instance. Your repository and your service class would work then with two different data contexts which would result in the failing update.

It's only a guess, I don't know the details of StructureMap. But with Unity (I am more familiar with), this would not work: Unity doesn't inject instances of a registered base class at places where a derived class is required. You need to register for the exact class type you want to inject.

Edit:
It would be a good idea to check if the DataContexts injected into the Repository and into the Service are really the same, for instance in your Edit method of the Controller:

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

(Make _dataContext in the Repository and _repository in the Service class public temporarily for that test.)

This way we can clearly distinguish if you have an injection problem or an EF problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文