更新实体框架中的对象
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尝试替换这一行...
...
(或者如果您还需要在其他地方解析
DbContext
,则添加这一行)您的
SqlRepository
想要有一个SqlDataContext
作为构造函数参数,而不是DbContext
。因此,当IRepository
得到解析和IMessagesServices
得到解析时,您的 DI 容器可能会创建两个新的SqlDataContext
实例,而不是使用注册的 SqlDataContext 实例。然后,您的存储库和服务类将使用两个不同的数据上下文,这将导致更新失败。这只是一个猜测,我不知道StructureMap的细节。但对于 Unity(我更熟悉),这是行不通的:Unity 不会在需要派生类的地方注入已注册基类的实例。您需要注册要注入的确切类类型。
编辑:
最好检查注入存储库和服务的 DataContext 是否确实相同,例如在控制器的
Edit
方法中:(在存储库中创建 _dataContext,在Service 类
public
暂时用于该测试。)这样我们就可以清楚地区分您是否有注入问题或 EF 问题。
Try to replace this line ...
...by
(or add this line if you also need
DbContext
to be resolved somewhere else)Your
SqlRepository
wants to have aSqlDataContext
as constructor parameter, not aDbContext
. So it could be the case the your DI container creates two new instances of theSqlDataContext
whenIRepository
gets resolved and whenIMessagesServices
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:(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.