Unable to update Foreign Key in Entity Framework 6

后端 未结 4 1355
迷失自我
迷失自我 2020-12-17 03:01

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


        
相关标签:
4条回答
  • 2020-12-17 03:21

    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;
            }
        }
    
    0 讨论(0)
  • 2020-12-17 03:25

    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;
        }
    
    0 讨论(0)
  • 2020-12-17 03:39

    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.

      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.

    See this post for more information.

    0 讨论(0)
  • 2020-12-17 03:43

    Basically this happens because EntryState.Modified just looks for scalar properties (primitive types) and with independent association (your case) you don't have it.

    There is a several ways to achieve this, @Yuliam has pointed some of them and here you can find more.

    0 讨论(0)
提交回复
热议问题