我正在尝试使用Entity Framework 6安全地插入/更新实体。我没有使用非线程安全且不建议用于生产的AddOrUpdate方法,我想我会先尝试在我的数据库中插入实体,如果由于主键冲突而失败,那么我会改为更新。我使用了数据库第一个模型。我的实体是一个用户,其主键= UserID,所有其他字段都可以为空。我需要Update Scenario来返回更新的实体,其中POST的值超过相应的值,而其他所有值都保留在DB中。
例如,我的用户实体有20个属性。我的POST可能只更新给定UserID的这些属性的一小部分。我需要返回的用户来显示更新的用户。
例如,我首先执行POST以插入UserID = x1的新用户,如下所示:
{ “UserID”:“x1”, “FirstName”:“用户名”, “LastName”:“用户姓”, “电子邮件”:“email@company.com” }
我的第二个POST是该用户的更新,以更新他们的电子邮件:
{ “UserID”:“x1”, “电子邮件”:“different_email@xyz.com” }
我需要第二个POST来向我显示我在第一个插入POST中设置的原始FirstName和LastName不是NULL。我在数据库中看到了原始的FirstName和LastName,但它没有显示在第二个POST的响应中。
问题是: (1)我在这里做错了什么? (2)我正在向DB发出2-3个查询。有没有更简洁的方法来减少到DB的往返而不影响线程安全性和并发性?
private UCBContext db = new UCBContext();
private bool InsertUser(ref User user)
{
try
{
db.Users.Add(user);
db.SaveChanges();
return (true);
}
catch { }
return (false);
}
private bool UpdateUser(ref User user)
{
try
{
db.Users.Attach(user);
DbEntityEntry entry = db.Entry(user);
foreach (var propertyName in entry.CurrentValues.PropertyNames)
{
var value = entry.CurrentValues[propertyName];
entry.Property(propertyName).IsModified = (propertyName != "UserID" && value != null);
}
db.SaveChanges();
return (true);
}
catch { }
return (false);
}
// POST: api/users = Insert/Update User
[ResponseType(typeof(User))]
public IHttpActionResult PostUser(User user)
{
if (!ModelState.IsValid){ return BadRequest(ModelState); }
bool ok = InsertUser(ref user);
if (!ok) { ok = UpdateUser(ref user); }
User dbuser = db.Users.Find(user.UserID);
if(dbuser == null) { return NotFound(); }
return Ok(dbuser);
}
public partial class User
{
public User()
{
this.Logins = 0;
}
public string UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public Nullable<int> Logins { get; set; }
}
答案 0 :(得分:0)
第二行返回原始用户对象...你应该这样做:
return Ok(dbuser);
而不是:
return Ok(user);
只是为此添加更多颜色 - 请记住,当您将用户对象传递给InsertUser或UpdateUser时,您基本上会传递它的副本。这就是为什么你需要根据UserID重新加载,然后返回这个刷新的用户对象。
答案 1 :(得分:0)
这是一种略有不同的方法。我还没有测试过这段代码。如果它不起作用,请告诉我们。
try
{
var existingUser = db.Users.Find(user.UserId); //or use db.Users.FirstOrDefault(...)
if(existingUser == null)
{
return false;
}
Type nType = user.GetType();
PropertyInfo[] newValues = nType.GetProperties();
foreach (PropertyInfo prop in newValues)
{
var propVal = prop.GetValue(user,null);
if(propVal!= null)
{
var eProp = existingUser.GetType().GetProperty(prop.Name);
if(eProp != null)
{
eProp.SetValue(existingUser, propVal, null);
}
}
}
db.SaveChanges();
return (true);
}
catch { }
return (false);