我有一个实体集国家,反映了数据库表'<'char(2),char(3),nvarchar(我的数据库中有50个。
我有一个解析器,它返回一个已解析国家的Country []数组,并且在以正确的方式更新它时遇到问题。我想要的是:采取一系列国家,对于那些尚未在数据库中插入它们的国家,以及那些现有更新,如果任何字段不同。怎么办呢?
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
//Code missing
}
}
我在想像
这样的东西for(var c in data.Except(db.Countries)) but it wount work as it compares on wronge fields.
希望以前有人遇到过这个问题,并为我提供解决方案。如果我不能使用Country对象并插入/更新它们的数组很容易,我不会看到使用框架的好处,因为从表演者我认为更快写一个自定义的sql脚本插入它们而不是ect检查一个国家在插入之前已经在数据库中了?
我将覆盖等于我的国家/地区类:
public partial class Country
{
public override bool Equals(object obj)
{
if (obj is Country)
{
var country = obj as Country;
return this.CountryTreeLetter.Equals(country.CountryTreeLetter);
}
return false;
}
public override int GetHashCode()
{
int hash = 13;
hash = hash * 7 + (int)CountryTreeLetter[0];
hash = hash * 7 + (int)CountryTreeLetter[1];
hash = hash * 7 + (int)CountryTreeLetter[2];
return hash;
}
}
然后做了:
var data = e.ParsedData as Country[];
using (var db = new entities())
{
foreach (var item in data.Except(db.Countries))
{
db.AddToCountries(item);
}
db.SaveChanges();
}
答案 0 :(得分:24)
我会直截了当地说:
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
foreach(var country in data)
{
var countryInDb = db.Countries
.Where(c => c.Name == country.Name) // or whatever your key is
.SingleOrDefault();
if (countryInDb != null)
db.Countries.ApplyCurrentValues(country);
else
db.Countries.AddObject(country);
}
db.SaveChanges();
}
}
我不知道您的应用程序必须运行多长时间,或者您的世界有多少个国家/地区。但我觉得这不是你必须考虑复杂性能优化的问题。
修改强>
只发出一个查询的替代方法:
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
var names = data.Select(c => c.Name);
var countriesInDb = db.Countries
.Where(c => names.Contains(c.Name))
.ToList(); // single DB query
foreach(var country in data)
{
var countryInDb = countriesInDb
.SingleOrDefault(c => c.Name == country.Name); // runs in memory
if (countryInDb != null)
db.Countries.ApplyCurrentValues(country);
else
db.Countries.AddObject(country);
}
db.SaveChanges();
}
}
答案 1 :(得分:9)
现代表格,使用后来的EF版本将是:
context.Entry(record).State = (AlreadyExists ? EntityState.Modified : EntityState.Added);
context.SaveChanges();
AlreadyExists
可以来自检查密钥或查询数据库以查看该项目是否已存在。
答案 2 :(得分:0)
您可以实现自己的IEqualityComparer<Country>
并将其传递给Except()
方法。假设您的Country对象具有Id
和Name
属性,那么该实现的一个示例可能如下所示:
public class CountryComparer : IEqualityComparer<Country>
{
public bool Equals(Country x, Country y)
{
return x.Name.Equals(y.Name) && (x.Id == y.Id);
}
public int GetHashCode(Country obj)
{
return string.Format("{0}{1}", obj.Id, obj.Name).GetHashCode();
}
}
并将其用作
data.Countries.Except<Country>(db, new CountryComparer());
虽然在您的情况下看起来您只需要提取新对象,但如果您的ID是Guid,则可以使用var newCountries = data.Where(c => c.Id == Guid.Empty);
。
最好的方法是检查Country.EntityState
属性并从那里采取有关值的操作(分离,修改,添加等)
您需要提供有关data
集合包含的内容的更多信息,即通过实体框架从数据库中检索的Country对象,在这种情况下可以跟踪其上下文,还是使用其他方式生成它们
答案 3 :(得分:0)
我不确定这是否是最佳解决方案,但我认为您必须从数据库中获取所有国家/地区,然后使用您的解析数据进行检查
void Method(object sender, DocumentLoadedEvent e)
{
var data = e.ParsedData as Country[];
using(var db = new DataContractEntities)
{
List<Country> mycountries = db.Countries.ToList();
foreach(var PC in data)
{
if(mycountries.Any( C => C.Name==PC.Name ))
{
var country = mycountries.Any( C => C.Name==PC.Name );
//Update it here
}
else
{
var newcountry = Country.CreateCountry(PC.Name);//you must provide all required parameters
newcountry.Name = PC.Name;
db.AddToCountries(newcountry)
}
}
db.SaveChanges();
}
}