C# EF4.1 DBContext:在一个Save()函数中插入/更新,不带标识PK
我有一个streets表,它有两个字符串列的组合作为主键,分别是postalcode和streetcode 对于EF4.1和DBContext,我想编写一个“Save”方法,然后获取一条街道(以未连接状态进入),检查它是否已经存在于数据库中。如果有,则发布更新;如果没有,则发布插入 仅供参考,保存这些街道的应用程序正在从文本文件中读取并保存这些街道(该文件中有数万条“街道线”) 我现在想到的是:C# EF4.1 DBContext:在一个Save()函数中插入/更新,不带标识PK,c#,entity-framework,entity-framework-4,primary-key,C#,Entity Framework,Entity Framework 4,Primary Key,我有一个streets表,它有两个字符串列的组合作为主键,分别是postalcode和streetcode 对于EF4.1和DBContext,我想编写一个“Save”方法,然后获取一条街道(以未连接状态进入),检查它是否已经存在于数据库中。如果有,则发布更新;如果没有,则发布插入 仅供参考,保存这些街道的应用程序正在从文本文件中读取并保存这些街道(该文件中有数万条“街道线”) 我现在想到的是: public void Save(Street street) {
public void Save(Street street)
{
var existingStreet = (
from s in streetContext.Streets
where s.PostalCode.Equals(street.PostalCode)
&& s.StreetCode.Equals(street.StreetCode)
select s
).FirstOrDefault();
if (existingStreet != null)
this.streetContext.Entry(street).State = System.Data.EntityState.Modified;
else
this.streetContext.Entry(street).State = System.Data.EntityState.Added;
this.streetContext.SaveChanges();
}
这是好的做法吗?这里的表演怎么样?因为对于每一条街道,它都会首先往返到db,看看它是否存在
尝试插入street(state=added)并捕获任何PK违规不是更好的性能明智之举吗?在catch块中,我可以将状态更改为modified并再次调用SaveChanges()。或者这不是一个好的做法
有什么建议吗
谢谢选择所有街道,然后为每个循环创建一个比较和更改状态的循环。循环完成后,调用saveChanges。这样,您只需对数据库进行几次调用,而不是数千次调用。如果数据库中已经存在street,则您的代码必须导致异常,因为您将从上下文加载它,然后尝试将另一个具有相同主键的实例附加到同一上下文实例 如果确实必须这样做,请使用以下代码:
public void Save(Street street)
{
string postalCode = street.PostalCode;
string streetCode = steet.StreetCode;
bool existingStreet = streetContext.Streets.Any(s =>
s.PostalCode == postalCode
&& s.StreetCode = steetCode);
if (existingStreet)
streetContext.Entry(street).State = System.Data.EntityState.Modified;
else
streetContext.Entry(street).State = System.Data.EntityState.Added;
streetContext.SaveChanges();
}
无论如何,在高度并发的系统中,它仍然不是可靠的解决方案,因为其他线程可以在您检查和后续插入之间插入相同的街道。感谢您的回复,但没有一个是真正令人满意的,所以我做了更多的研究,并重新编写了这样的方法,满足了我的需要 ps:重命名了方法to Import(),因为我发现用于从外部源(如我的示例中的文本文件)批量导入实体的方法的名称更合适 ps2:我知道捕捉异常并让它安静地死去不是最好的做法,但在我的特殊情况下,我没有必要对它做任何事情。它只是一种发现数据库中已经存在该行的方法
public void Import(Street street)
{
try
{
this.streetContext.Entry(street).State = System.Data.EntityState.Added;
this.streetContext.SaveChanges();
}
catch (System.Data.Entity.Infrastructure.DbUpdateException dbUex)
{
this.streetContext.Entry(street).State = System.Data.EntityState.Modified;
this.streetContext.SaveChanges();
}
finally
{
((IObjectContextAdapter)this.streetContext).ObjectContext.Detach(street);
}
}
谢谢,但我认为从性能角度来看,一次在内存中加载20K street实体并不是一个真正的选择