我正在尝试对外键进行简单更新,但脚本永远不会被发送过来。
以下是我正在使用的代码:
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。
人物实体:
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; }
}
我在这里缺少什么?
请帮忙!
答案 0 :(得分:8)
因为您正在与独立协会合作。你可以
在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();
或者您可以使用断开连接的对象,但您需要手动管理关系。
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即可更新外键。
有关详细信息,请参阅this post。
答案 1 :(得分:1)
这就是我最终建造到凌晨时分,我们应该再重构一次......
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;
}
}
答案 2 :(得分:1)
基本上会发生这种情况,因为EntryState.Modified
只查找标量属性(原始类型)并且与您没有独立关联(您的情况)。
有几种方法可以达到这个目的,@ Yuliam指出了其中的一些方法 here你可以找到更多。
答案 3 :(得分: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;
}