我有一个街道表,它有两个作为PK的字符串列的组合,是邮政编码和街道代码。
使用EF4.1和DBContext,我想写一个“保存”方法而不是一个街道(进入未连接状态),检查数据库中是否已经存在。如果是,则发出UPDATE,如果没有,则发出INSERT。
仅供参考,保存这些街道的应用程序正在从文本文件中读取它们并保存它们(该文件中有几万条“街道线”)。
我现在想出的是:
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();
}
这是好习惯吗?这里的表现怎么样?导致每个街道首先进行数据包往返以查看它是否存在。
尝试插入街道(状态=已添加)并捕获任何违反PK的情况不会更好吗?在catch块中,我可以将状态更改为modified并再次调用SaveChanges()。或者那不是一个好习惯吗?
有什么建议吗?
由于
答案 0 :(得分:1)
选择所有街道,然后为每个比较和更改状态的循环创建一个。循环完成后,调用saveChanges。这样你只需要调用db而不是几个thousends
答案 1 :(得分:1)
感谢回复,但没有一个真的令人满意,所以我做了一些研究并重写了这样的方法,满足了我的需要。
ps:将方法重命名为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);
}
}
答案 2 :(得分:0)
如果数据库中已存在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();
}
无论如何,它仍然不是高度并发系统中的可靠解决方案,因为其他线程可以在您检查和后续插入之间插入相同的街道。