实体框架AddOrUpdateOrDontBother与嵌套

时间:2013-06-22 20:09:58

标签: 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; }
}

假设您有一个控制器

public class RecordController 
{
    ...

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

    ...
}

并且您的Root控制器已从客户端收到一个包含以下更改的模型:属性A是全新的,尚未添加到数据库并且需要创建,属性{{1数据库中已存在,需要更新,属性B未更改。

操作C不知道属性更改是什么,只需要正确更新Save并创建缺失或更新现有子模型,也可能有些Record }类也可能有自己的嵌套更改,所以我需要一个方法,以某种方式通过模型递归比较新模型与现有模型,并将应用适当的更改。那我该怎么做呢?

1 个答案:

答案 0 :(得分:0)

我最终将每个模型和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;
            }
        }
    }
相关问题