什么是最有效的方法来实现更新行,如果它存在,否则插入新的行逻辑使用实体框架?或者这有什么规律吗?
当前回答
试试这个算法
public void InsertOrUpdate(Item item)
{
using (var context = new ItemContext())
{
var existedItem = context.Items.Where(x => x.Id==item.Id).FirstOrDefault();
if(existedItem != null)
{
context.Entry(existedItem).CurrentValues.SetValues(item);
//or only if you want to update some special properties
existedItem.Prop1=item.Prop1;
existedItem.Prop2=item.Prop2
context.Entry(existedItem).State =EntityState.Modified;
//-----------
}
else
{
context.Items.Add(item);
}
context.SaveChanges();
}
}
其他回答
@LadislavMrnka的替代答案。这是实体框架6.2.0。
如果你有一个特定的DbSet和一个需要更新或创建的项:
var name = getNameFromService();
var current = _dbContext.Names.Find(name.BusinessSystemId, name.NameNo);
if (current == null)
{
_dbContext.Names.Add(name);
}
else
{
_dbContext.Entry(current).CurrentValues.SetValues(name);
}
_dbContext.SaveChanges();
但是,这也可以用于具有单个主键或复合主键的通用DbSet。
var allNames = NameApiService.GetAllNames();
GenericAddOrUpdate(allNames, "BusinessSystemId", "NameNo");
public virtual void GenericAddOrUpdate<T>(IEnumerable<T> values, params string[] keyValues) where T : class
{
foreach (var value in values)
{
try
{
var keyList = new List<object>();
//Get key values from T entity based on keyValues property
foreach (var keyValue in keyValues)
{
var propertyInfo = value.GetType().GetProperty(keyValue);
var propertyValue = propertyInfo.GetValue(value);
keyList.Add(propertyValue);
}
GenericAddOrUpdateDbSet(keyList, value);
//Only use this when debugging to catch save exceptions
//_dbContext.SaveChanges();
}
catch
{
throw;
}
}
_dbContext.SaveChanges();
}
public virtual void GenericAddOrUpdateDbSet<T>(List<object> keyList, T value) where T : class
{
//Get a DbSet of T type
var someDbSet = Set(typeof(T));
//Check if any value exists with the key values
var current = someDbSet.Find(keyList.ToArray());
if (current == null)
{
someDbSet.Add(value);
}
else
{
Entry(current).CurrentValues.SetValues(value);
}
}
在我看来,有了新发布的EntityGraphOperations for Entity Framework Code First,你可以省去为定义图中所有实体的状态而编写一些重复的代码。我是这个产品的作者。我已经在github、code-project(包括一步一步的演示和一个示例项目,可以下载)和nuget上发布了它。
它将自动将实体的状态设置为已添加或已修改。如果它不再存在,您将手动选择必须删除哪些实体。
示例:
假设我有一个Person对象。一个人可以有很多电话,一个文件,也可以有一个配偶。
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public int Age { get; set; }
public int DocumentId {get; set;}
public virtual ICollection<Phone> Phones { get; set; }
public virtual Document Document { get; set; }
public virtual PersonSpouse PersonSpouse { get; set; }
}
我想确定图中包含的所有实体的状态。
context.InsertOrUpdateGraph(person)
.After(entity =>
{
// Delete missing phones.
entity.HasCollection(p => p.Phones)
.DeleteMissingEntities();
// Delete if spouse is not exist anymore.
entity.HasNavigationalProperty(m => m.PersonSpouse)
.DeleteIfNull();
});
另外,如你所知,在定义电话实体的状态时,唯一的键属性可以发挥作用。出于这种特殊目的,我们有ExtendedEntityTypeConfiguration<>类,它继承自EntityTypeConfiguration<>。如果我们想使用这样的特殊配置,那么我们必须从ExtendedEntityTypeConfiguration<>继承我们的映射类,而不是EntityTypeConfiguration<>。例如:
public class PhoneMap: ExtendedEntityTypeConfiguration<Phone>
{
public PhoneMap()
{
// Primary Key
this.HasKey(m => m.Id);
…
// Unique keys
this.HasUniqueKey(m => new { m.Prefix, m.Digits });
}
}
这是所有。
纠正
public static void InsertOrUpdateRange<T, T2>(this T entity, List<T2> updateEntity)
where T : class
where T2 : class
{
foreach(var e in updateEntity)
{
context.Set<T2>().InsertOrUpdate(e);
}
}
public static void InsertOrUpdate<T, T2>(this T entity, T2 updateEntity)
where T : class
where T2 : class
{
if (context.Entry(updateEntity).State == EntityState.Detached)
{
if (context.Set<T2>().Any(t => t == updateEntity))
{
context.Set<T2>().Update(updateEntity);
}
else
{
context.Set<T2>().Add(updateEntity);
}
}
context.SaveChanges();
}
试试这个算法
public void InsertOrUpdate(Item item)
{
using (var context = new ItemContext())
{
var existedItem = context.Items.Where(x => x.Id==item.Id).FirstOrDefault();
if(existedItem != null)
{
context.Entry(existedItem).CurrentValues.SetValues(item);
//or only if you want to update some special properties
existedItem.Prop1=item.Prop1;
existedItem.Prop2=item.Prop2
context.Entry(existedItem).State =EntityState.Modified;
//-----------
}
else
{
context.Items.Add(item);
}
context.SaveChanges();
}
}
使用Any检查现有行。
public static void insertOrUpdateCustomer(Customer customer)
{
using (var db = getDb())
{
db.Entry(customer).State = !db.Customer.Any(f => f.CustomerId == customer.CustomerId) ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
}
}
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>
- 如何转换列表<字符串>列表<int>?
- c#对象列表,我如何得到一个属性的和