简体   繁体   English

工作单元/存储库模式以及使用EF更新实体

[英]Unit of Work/Repository pattern and updating entities using EF

I'm trying to get to know UoW pattern a bit better as I like its concept, but currently I'm having a hard times saving entities. 我想更好地了解UoW模式,因为我喜欢它的概念,但是目前我在保存实体方面遇到困难。

The problem is that when my Edit (POST) action in my controller fires only parent entity gets saved and the child entities are intact ie I get the following error: 问题是当控制器中的我的Edit(POST)操作触发时,仅保存了父实体,而子实体完好,即出现以下错误:

Attaching an entity of type 'Access.Models.ApplicationParameter' failed because another entity of the same type already has the same primary key value. 附加类型'Access.Models.ApplicationParameter'的实体失败,因为相同类型的另一个实体已经具有相同的主键值。 This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. 如果图形中的任何实体具有相互冲突的键值,则使用“附加”方法或将实体的状态设置为“不变”或“修改”时,可能会发生这种情况。 This may be because some entities are new and have not yet received database-generated key values. 这可能是因为某些实体是新实体,尚未收到数据库生成的键值。 In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate. 在这种情况下,请使用“添加”方法或“已添加”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

Note: Parent entity Application can have multiple child ApplicationParameter entities. 注意:父实体Application可以具有多个子ApplicationParameter实体。

Controller 控制者

    [HttpPost]
    public ActionResult Edit(ApplicationVM applicationVM)
    {
        Application application = ViewModelToModel(applicationVM);
        uow.ApplicationRepository.Update(application);

        foreach (var applicationParameterVM in applicationVM.ApplicationParameters)
        {
            ApplicationParameter applicationParameter = ViewModelToModel(applicationParameterVM);

            bool exists = uow.ApplicationParameterRepository.Exists(applicationParameter.idApplicationParameter);

            if (exists)
            {
                uow.ApplicationParameterRepository.Update(applicationParameter);
            }
            else
            {
                uow.ApplicationParameterRepository.Insert(applicationParameter);
            }
        }

        uow.Save();
        return View(applicationVM);
    }

ApplicationParameterRepository.cs (just Update snippet) ApplicationParameterRepository.cs(仅更新代码段)

    public void Update(ApplicationParameter entity)
    {
        db.Entry(entity).State = EntityState.Modified;
    }

UOW.cs UOW.cs

public class UnitOfWork : IDisposable
{
    private AMEntities db = null;

    public UnitOfWork()
    {
        db = new AMEntities();
    }

    //Add all the repository handles here
    IApplicationRepository applicationRepository = null;
    IApplicationParameterRepository applicationParameterRepository = null;
    IApplicationUserRepository applicationUserRepository = null;

    //Add all the repository getters here
    public IApplicationRepository ApplicationRepository
    {
        get
        {
            if (applicationRepository == null)
            {
                applicationRepository = new ApplicationRepository(db);
            }
            return applicationRepository;
        }
    }
    public IApplicationParameterRepository ApplicationParameterRepository
    {
        get
        {
            if (applicationParameterRepository == null)
            {
                applicationParameterRepository = new ApplicationParameterRepository(db);
            }
            return applicationParameterRepository;
        }
    }
    public IApplicationUserRepository ApplicationUserRepository
    {
        get
        {
            if (applicationUserRepository == null)
            {
                applicationUserRepository = new ApplicationUserRepository(db);
            }
            return applicationUserRepository;
        }
    }

    public void Save()
    {
        db.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                db.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Question: What should I do to have those child entities saved? 问题:如何保存这些子实体?

Ensure you establish the relationship between applicationParameter and application . 确保您建立了applicationParameterapplication之间的关系。 There are at least three ways to do that using navigation properties or Ids, and I don't see in your code a line like this: 至少有三种方法可以使用导航属性或Id来做到这一点,而且我在您的代码中看不到这样的行:

1. 1。

// if application have unique Id, for example it already has been saved in db
applicationParameter.ApplicationId = application.Id; 

2. 2。

applicationParameter.Application = application;

3. 3。

//if application is a EF-generated proxy 
application.ApplicationParameters.Add(applicationParameter); 

Also, in simple cases you don't need to set EntityState if entity has been added to context properly. 同样,在简单情况下,如果已将实体正确添加到上下文中,则无需设置EntityState

You have 2 options as far as I see it. 据我所知,您有2个选择。

  1. The easiest thing to do would be to get the entity at the start of your Edit action. 最简单的方法是在“编辑”操作开始时获取实体。 If the result is null, then add a new one otherwise update the entity with the new values and save. 如果结果为空,则添加一个新值,否则使用新值更新实体并保存。 This will ensure the parent entity and all children are in the same context. 这将确保父实体和所有子实体处于同一上下文中。

  2. The other way is to use self tracking entities. 另一种方法是使用自我跟踪实体。 Take a look at Self Tracking Entities . 看一下自我跟踪实体 This way you handle the state of your entities and not EF. 这样,您就可以处理实体而不是EF的状态。

The issue is you have only set the state of the parent to updated, each childs state is still added, so its trying to add the child entities instead of update them. 问题是您只将父级的状态设置为已更新,每个子级的状态仍会添加,因此它试图添加子级实体而不是更新它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM