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

mad*_*ora 0 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");
        }            
    }
}
Run Code Online (Sandbox Code Playgroud)

写储存

//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();
    }
}
Run Code Online (Sandbox Code Playgroud)

阅读存储库

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Cor*_*ith 5

从你的MyController代码看起来你已经在使用Inversion of Control框架,所以更新你的ReadRepositoryWriteRepository类如下:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

无论您ReadRepositoryWriteRepository取决于实例MyDBEntities做的工作,所以你应该指定这些类的构造函数依赖,并让你控制框架手柄的反转创造它,而不是创造的新实例MyDBEntities自己.

确保在您的Inversion of Control框架的注册中,您将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 ...
    }
}
Run Code Online (Sandbox Code Playgroud)

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 ...
}
Run Code Online (Sandbox Code Playgroud)