简体   繁体   English

无法更新实体框架 6 中的外键

[英]Unable to update Foreign Key in Entity Framework 6

I am trying to do a simple update to the foreign key but the script never get sent over.我正在尝试对外键进行简单的更新,但脚本永远不会被发送。

Here is the code I am using:这是我正在使用的代码:

using (var db = new MyContext())
{
      db.Entry<Contact>(newContact).State = EntityState.Modified;
      newContact.ContactOwner = db.Person.Find(3);
      db.SaveChanges();
}

EF6 update the rest of the column in the Persons table but it is not updating the Contact_Id in Persons table. EF6 更新 Persons 表中列的其余部分,但不会更新 Persons 表中的 Contact_Id。

Person entity:个人实体:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Contact> ContactList { get; set; }
}

Contact entity:联系实体:

public class Contact
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string TelNo { get; set; }
    public Person ContactOwner { get; set; }
}

What am I missing here?我在这里缺少什么?

Please help!请帮忙!

Since you are working with independent association.由于您正在与独立协会合作。 You can either你可以

  • Adding and removing the relationship from ContactList , but you need to retrieve from both Person .ContactList添加和删​​除关系,但您需要从两个Person检索。

     db.Entry(newContact).State = EntityState.Modified; var p1 = db.Set<Person>().Include(p => p.ContactList) .FirstOrDefault(p =>p.Id == 1); p1.ContactList.Remove(newContact); var p3 = db.Set<Person>().Include(p => p.ContactList) .FirstOrDefault(p => p.Id == 3); p3.ContactList.Add(newContact); db.SaveChanges();
  • Or you can use disconnected object, but you need to manually manage the relationship.或者您可以使用断开连接的对象,但您需要手动管理关系。

     db.Entry(newContact).State = EntityState.Modified; var p1 = new Person { Id = 1 }; db.Entry(p1).State = EntityState.Unchanged; var p3 = new Person { Id = 3 }; db.Entry(p3).State = EntityState.Unchanged; var manager = ((IObjectContextAdapter)db).ObjectContext.ObjectStateManager; manager.ChangeRelationshipState(newContact, p1, item => item.ContactOwner, EntityState.Deleted); manager.ChangeRelationshipState(newContact, p3, item => item.ContactOwner, EntityState.Added); db.SaveChanges();

PS聚苯乙烯

You might need to reconsider adding foreign key value, to make everything easier, updating foreign key just by mentioning the Id.您可能需要重新考虑添加外键值,以简化一切,只需提及 Id 即可更新外键。

See this post for more information.有关更多信息,请参阅此帖子

This is what I ended up building till the late hours of the morning, chould/should be refactored some more...这就是我最终构建到凌晨的东西,应该/应该再重构一些......

   protected static async Task<int> SaveEntity<t>(t obj) where t : BaseModel
    {
        try
        {
            using (DatabaseContext db = GetDbContext())
            {

                //get the basemodel/fk reference properties
                IEnumerable<PropertyInfo> props = obj.GetType().GetProperties().Where(p => p.PropertyType.BaseType == typeof(BaseModel));

                if (obj.Id <= 0)
                {//insert

                    db.Entry(obj).State = EntityState.Added;

                    //set fk reference props to unchanged state
                    foreach (PropertyInfo prop in props)
                    {
                        Object val = prop.GetValue(obj);
                        if (val != null)
                        {
                            db.Entry(val).State = EntityState.Unchanged;
                        }
                    }

                    //do insert
                    return await db.SaveChangesAsync();

                }
                else
                {//update

                    //get the posted fk values, and set them to null on the obj (to avaid dbContext conflicts)
                    Dictionary<string, int?> updateFKValues = new Dictionary<string, int?>();
                    foreach (PropertyInfo prop in props)
                    {
                        BaseModel val = (BaseModel)prop.GetValue(obj);
                        if (val == null)
                        {
                            updateFKValues.Add(prop.Name, null);
                        }
                        else
                        {
                            updateFKValues.Add(prop.Name, val.Id);
                        }

                        prop.SetValue(obj, null);
                    }

                    //dbContext creation may need to move to here as per below working example
                    t dbObj = (t)db.Set(typeof(t)).Find(new object[] { obj.Id }); //this also differs from example

                    //update the simple values
                    db.Entry(dbObj).CurrentValues.SetValues(obj);

                    //update complex values
                    foreach (PropertyInfo prop in props)
                    {
                        Object propValue = null;
                        if (updateFKValues[prop.Name].HasValue)
                        {
                            propValue = (BaseModel)db.Set(prop.PropertyType).Find(new object[] { updateFKValues[prop.Name] });
                        }

                        prop.SetValue(dbObj, propValue);
                        if (propValue != null)
                        {
                            db.Entry(propValue).State = EntityState.Unchanged;
                        }

                    }

                    //do update
                    return await db.SaveChangesAsync();

                }

            }
        }
        catch (Exception ex)
        {
            ExceptionHelper.Log(ex);
            throw;
        }
    }

Basically this happens because EntryState.Modified just looks for scalar properties ( primitive types) and with independent association (your case) you don't have it.基本上发生这种情况是因为EntryState.Modified只是寻找标量属性(原始类型)并且具有独立关联(您的情况),您没有它。

There is a several ways to achieve this, @Yuliam has pointed some of them and here you can find more.有几种方法可以实现这一点,@Yuliam 指出了其中的一些,在这里您可以找到更多。

This solution worked for me when needing to update the main object and it's foreign key objects attached.当需要更新主对象及其附加的外键对象时,此解决方案对我有用。

    public virtual async Task<Result<TEntity>> Update<TEntity>(TEntity entity) where TEntity : class
    {
        Result<TEntity> returnResult = new Result<TEntity>();

        try
        {
            //get the fk reference properties
            IEnumerable<PropertyInfo> props = entity.GetType().GetProperties().Where(p => p.PropertyType.BaseType == typeof(object));

            //set fk reference props to modified state
            foreach (PropertyInfo prop in props)
            {
                Object val = prop.GetValue(entity);
                if (val != null)
                {
                    dbContext.Entry(val).State = EntityState.Modified;
                }
            }


            dbContext.Entry(entity).State = EntityState.Modified;
            await dbContext.SaveChangesAsync();
            returnResult.SetSuccess(result: entity);
        }
        catch (Exception e)
        {
            log.Error(e);
            returnResult.SetError(exception: e);
        }
        
        return returnResult;
    }

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

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