c# - 具有嵌套的 Entity Framework AddOrUpdateOrDontBother

标签 c# asp.net-mvc entity-framework

我首先在以下模型中使用 EF 代码:

public class Root
{
    public ChildA A { get; set; }
    public ChildB B { get; set; }
    public ChildC C { get; set; }
}

假设你有一个 Controller

public class RecordController 
{
    ...

    public void Save(Root root)
    {
        ...
    }

    ...
}

并且您的 Root Controller 已收到来自客户端的模型,其中包含以下更改:属性 A 是全新的,尚未添加到数据库中,需要添加已创建,属性 B 已存在于数据库中,需要更新,属性 C 未更改。

Action Save 并不知道属性变化是什么,它只需要适本地更新Record 并创建丢失的或更新现有的子模型,这也是可能的一些 Child 类也可能有自己的嵌套更改,因此我需要一种方法,该方法将以某种方式递归模型,将新模型与现有模型进行比较,并应用适当的更改。那我该怎么做呢?

最佳答案

我最终将我的每个模型和 ViewModel 类与 EntityState 属性连接起来,所以现在当我更改某些属性时,我将 EntityState 设置为 changed 状态,当我创建一个时,我将属性设置为状态 Added,最初模型初始化为 Unchanged 状态,基本上它看起来像下面这样:

[Table("City")]
[KnownType(typeof(Country))]
public class City
{
    public City()
    {
        Airports = new List<Airport>();
        LastUpdate = DateTime.Now;
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Int32 Id { get; set; }

    public Int32? CountryId { get; set; }

    [StringLength(50)]
    public String Name { get; set; }

    [Range(-12, 13)]
    public Int32? TimeZone { get; set; }

    public Boolean? SummerTime { get; set; }
    public DateTime? LastUpdate { get; set; }

    [ForeignKey("CountryId")]
    public virtual Country Country { get; set; }

    [NotMapped]
    public EntityState? EntityState { get; set; } // <----------- Here it is
}

然后在服务器上我执行以下操作

    [HttpPost, HttpGet]
    public HttpResponseMessage SaveRecord(RecordViewModel record)
    {
        var model = Mapper.Map<Record>(record);

        if (!ModelState.IsValid)
        {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }

        db.Attach(model);

        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
        }

        return Request.CreateResponse(HttpStatusCode.OK);
    }

这是 Attach 方法的实现:

    public void Attach(City entity)
    {
        if (entity != null)
        {
            Attach(entity.Country);

            AttachAndMarkAs(entity, entity.EntityState ?? EntityState.Added, instance => instance.Id);
        }
    }
    public void Attach(Country entity)
    {
        if (entity != null)
        {
            AttachAndMarkAs(entity, entity.EntityState ?? EntityState.Added, instance => instance.Id);
        }
    }

AttachAndMarkAs 具有以下实现:

    public void AttachAndMarkAs<T>(T entity, EntityState state, Func<T, object> id) where T : class
    {
        var entry = Entry(entity);

        if (entry.State == EntityState.Detached)
        {
            var set = Set<T>();

            T attachedEntity = set.Find(id(entity));

            if (attachedEntity != null)
            {
                var attachedEntry = Entry(attachedEntity);

                attachedEntry.CurrentValues.SetValues(entity);
            }
            else
            {
                entry.State = state;
            }
        }
    }

关于c# - 具有嵌套的 Entity Framework AddOrUpdateOrDontBother,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17254849/

相关文章:

c# - 失败 - 下载由 Ionic.Zip.dll 制作的 zip 文件时出现网络错误

javascript - AngularJS - 从 .NET Controller 生成 View 只执行一次

mysql - 无法捕获 MySqlException [Entity Framework WebAPI]

ASP.NET 如何最好地使用 EntityDataSource 在 gridview 上添加删除确认

c# - 如何使用计时器每 x 秒更改一次标签文本

c# - 当属性抛出错误时,如何将其设置为空值?

.net - ASP.NET MVC 中 runat ="server"标签的状态是什么?

asp.net-mvc - 存储库模式 - 如何正确处理 JOIN 和复杂查询?

javascript - 正则表达式限制小数点后两位

css - 区域布局中的链接到位于 ASP NET MVC 应用程序根目录中的 Content\Css 文件夹