无法在Entity Framework 6中更新外键

7

我想对外键进行简单的更新,但脚本从未被发送过。

以下是我使用的代码:

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

EF6更新了Persons表中其余列的内容,但未更新Persons表中的Contact_Id。

Person实体:

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

联系人实体:

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

我这里漏了什么?

请帮忙一下!


请问您能展示一下 Persons 类吗? - Yuliam Chandra
@YuliamChandra 我已经添加了Person和Contact类。 - foo0110
@YuliamChandra编辑了问题,应该是相反的。 “newContact”是一个修改后的实体。 - foo0110
д»Қ然жңүй”ҷеҲ«еӯ—newContact.Personе’Ңpublic Person ContactOwner { get; set; }пјҢnewContactжҳҜеҗҰе·Із»ҸеӯҳеңЁеҜ№д»»дҪ•Personзҡ„еј•з”Ёпјҹ - Yuliam Chandra
@YuliamChandra 现在应该是正确的了,抱歉我之前疏忽了。 "newContact" 具有对另一个 ID=1 的 "Person" 实体的现有引用。 - foo0110
显示剩余2条评论
4个回答

8

由于您正在使用独立协会,您可以选择:

  • Adding and removing the relationship from ContactList, but you need to retrieve from both 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

您可能需要重新考虑添加外键值,以使更新外键时只需提及 ID,这样可以让一切变得更加容易。

有关更多信息,请参见此帖子


我尝试了您提供的代码,但仍然没有看到Person_Id在EF6的更新脚本中生成到Contact表中。 - foo0110
刚刚注意到你编辑过的答案,经过查看提供的链接和你的回答后,我将“PersonId”属性添加到联系人实体中,现在一切都正常了!我同时使用“独立关联”和“外键关联”。 - foo0110

2
这是我在凌晨建造的东西,可能需要进一步重构...
   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;
        }
    }

1
基本上这是因为EntryState.Modified只查找标量属性(原始数据类型),而在独立关联中(您的情况),您没有它。
有几种方法可以实现这一点,@Yuliam指出了其中的一些方法,在这里你可以找到更多。

0

当我需要更新主对象及其附加的外键对象时,这个解决方案对我很有用。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接