实体框架创建重复实体

时间:2013-06-24 15:35:12

标签: c# entity-framework asp.net-mvc-4 asp.net-web-api

修改

我已经根据我的问题录制了一个截屏视频,您可以找到它here,请查看您是否有时间。

我有以下代码应该执行AddOrUpdate功能,但是重新创建所有现有记录,因此我有几个纽约,几个美国。我正在从客户端传输EntityState,因此如果客户端上的数据发生更改,客户端会相应地更新EntityState属性并将其发送到服务器。

    [HttpPost, HttpGet, HttpPut]
    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, Mapper.Map<RecordViewModel>(model));
    }

我正在附加具有以下功能的实体

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

                if (state != EntityState.Unchanged)
                {
                    attachedEntry.CurrentValues.SetValues(entity);
                    attachedEntry.State = state;
                }
            }
            else
            {
                entry.State = state;
            }
        }
    }

通过以下方式转发:

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

我不明白代码的哪一部分处理添加实体而不是更新它们,因为EntityState值是正确的......

2 个答案:

答案 0 :(得分:3)

如果您使用简单的int作为您的ID,则可以使用以下方法。

public abstract class BaseEntity
{
    public int Id { get; set; }
}

public void AddOrUpdate<T> (T entity) where T : BaseEntity
{
   if(entity.Id > 0){
      Entry(entity).State = EntityState.Modified;
   }
   else
   {
      Set<T>().Add(entity);
   }
}

// 

var model = Mapper.Map<Record>(record);
db.AddOrUpdate(model);
db.SaveChanges();

答案 1 :(得分:2)

当您以编程方式更改父实体的状态时,需要注意实体框架如何处理子实体/引用实体。

看看这个article,它总结了许多不同情况下的工作原理。

在下面的示例中,您可能会认为所有引用的实体都会自动设置为Modifiied

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Modified;
    // Do some more work... 
    context.SaveChanges();
}

但实际上,他们不会。 如文章所述:

  

如果您有多个需要标记为已修改的实体   应该单独为每个实体设置状态。

最后,当AddOrUpdatePrimaryKey时,您需要处理Int特定案例的方式:

using (var context = new BloggingContext())
{
   context.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added : EntityState.Modified;

   context.SaveChanges();
}