【问题标题】:MVC Repository Pattern with Entity Framework and Updating a Record带有实体框架和更新记录的 MVC 存储库模式
【发布时间】:2016-09-19 00:37:06
【问题描述】:

我正在尝试在 MVC 应用程序中使用带有 EntityFramework 的存储库模式来更新记录,但是 db.SaveChanges() 方法没有保存到数据库中。我没有收到任何错误,我可以单步执行代码并查看正确的变量是否被传递,以及记录变量是否得到更新。

根据我一直在阅读的内容,我认为我的问题是我的数据库上下文 (MyDBEntities) 有两个实例。问题可能是我的创建 MyDBEntities 实例的 ReadRepository 被注入到 WriteRepository 中,WriteRepository 也创建了一个实例 MyDBEntities。我不确定如何将实体注入存储库(假设这是我需要做的)。

如果我尝试在db.SaveChanges() 之前添加类似db.MyTable.Attach(record); 的内容,我会在下面收到此错误,这让我觉得我需要注入MyDBEntities()

An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

控制器

public class MyController : Controller
{
    private IWriteRepository _writeRepository;

    public MyController(IWriteRepository writeRepository)
    {
        _writeRepository = writeRepository;
    }

    [HttpPost]
    public ActionResult MyPostMethod(MyViewModel model)
    {
        try
        {
            //Send to the repository to edit a record
            writeRepository.EditRecord(model);

            return new HttpStatusCodeResult(HttpStatusCode.OK);
        }
        catch
        {
            throw new HttpException(500, "Internal Server Error");
        }            
    }
}

写存储库

//The ReadRepository is injected into the WriteRepository to grab records from the database
public class WriteRepository : IWriteRepository
{
    private MyDBEntities db = new MyDBEntities();
    private IReadRepository _readRepository;

    public WriteRepository(IReadRepository readeadRepository)
    {
        _readRepository = readRepository;
    }        

    public void EditRecord(MyViewModel model)
    {
        //Get the specific record to be updated
        var record = readRepository.GetRecord(model.ID);

        //Update the data
        record.FirstName = model.Name;

        //This isn't saving
        db.SaveChanges();
    }
}

读取存储库

public class ReadRepository : IReadRepository
{
    private MyDBEntities db = new MyDBEntities();

    //Provides the record to the write repository to edit
    public MyTable GetRecord(int ID)
    {
        var record = (from t in db.MyTable
                      where t.ID == ID
                      select t).SingleOrDefault();

        return record;
    }
}

【问题讨论】:

标签: asp.net-mvc entity-framework dependency-injection repository-pattern


【解决方案1】:

从您的 MyController 代码看来,您已经在使用控制反转框架,因此请将您的 ReadRepositoryWriteRepository 类更新为如下:

读取存储库

public class ReadRepository : IReadRepository
{
    private MyDBEntities db;

    public ReadRepository(MyDBEntities myDbEntities) 
    {
        db = myDbEntities;
    }

    //Provides the record to the write repository to edit
    public MyTable GetRecord(int ID)
    {
        var record = (from t in db.MyTable
                      where t.ID == ID
                      select t).SingleOrDefault();

        return record;
    }
}

WriteRepository

public class WriteRepository : IWriteRepository
{
    private MyDBEntities db;
    private IReadRepository _readRepository;

    public WriteRepository(MyDBEntities myDbEntities, IReadRepository readeadRepository)
    {
        db = myDbEntities;
        _readRepository = readRepository;
    }        

    public void EditRecord(MyViewModel model)
    {
        //Get the specific record to be updated
        var record = readRepository.GetRecord(model.ID);

        //Update the data
        record.FirstName = model.Name;

        //This isn't saving
        db.SaveChanges();
    }
}

您的 ReadRepositoryWriteRepository 都依赖于 MyDBEntities 的实例来工作,因此您应该在它们的构造函数中指定该依赖项类并让您的控制反转框架处理创建它,而不是自己创建 MyDBEntities 的新实例。

确保在您的控制反转框架的注册中,您将您的 MyDBEntities 实例注册为范围内或每个请求,而不是临时的。您要确保在每个请求中,您的 ReadRepositoryWriteRepository 都被注入您的 MyDBEntities 类的同一个实例,而不是两个单独的实例就像现在一样。

如下更新您的 Unity 配置:

UnityConfig.cs

在每个请求范围内向 Unity 注册您的 MyDBEntities 类。

public class UnityConfig
{
    // ... other methods ...

    public static void RegisterTypes(IUnityContainer container)
    {
        // ... other registrations ...
        container.RegisterType<IReadRepository, ReadRepository>();
        container.RegisterType<IWriteRepository, WriteRepository>();
        container.RegisterType<MyDBEntities>(new PerRequestLifetimeManager());
        // ... other registrations ...
    }
}

UnityMvcActivator.cs

通过取消注释 TODO 下的行,在 Unity 中启用 per-request 范围。

public static class UnityWebActivator
{
    public static void Start()
    {
        // ... start code ...
        // TODO: Uncomment if you want to use PerRequestLifetimeManager
        Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
    }

    // ... other methods ...
}

【讨论】:

  • 出色的答案。你正走在我需要的轨道上。我实际上将 Unity 用于框架,但不知道要注册什么或如何注册最后一部分的实体。
  • 好的,我用 Unity 的注册更新了我的答案。
  • 感谢您的更新。如果一切正常,我会尝试一下并将其标记为答案。
  • 我们能得到一些反馈吗,@madvora?请标记为已回答或添加额外的跟进 cmets。僵尸问题伤害了每个人。
猜你喜欢
  • 2015-07-15
  • 1970-01-01
  • 2010-12-11
  • 2013-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多