具有实体框架和更新记录的MVC存储库模式

时间:2016-05-21 22:59:21

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

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

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

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

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

CONTROLLER

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

WRITE REPOSITORY

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

READ REPOSITORY

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

1 个答案:

答案 0 :(得分:5)

从您的 MyController 代码看起来您​​已经在使用Inversion of Control框架,因此请将 ReadRepository WriteRepository 类更新为如下:

<强> ReadRepository

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

您的 ReadRepository WriteRepository 都依赖于 MyDBEntities 的实例来完成工作,所以您应该在那些的构造函数中指定该依赖项让您的Inversion of Control框架处理创建它而不是自己创建 MyDBEntities 的新实例。

确保在您的Inversion of Control框架的注册中,您将 MyDBEntities 实例注册为作用域或每个请求,而不是瞬态。您希望确保在每个请求中 ReadRepository WriteRepository 都注入了 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中的每请求范围。

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 ...
}