EntityFramework,如果不存在则插入,否则更新

时间:2011-08-06 10:34:44

标签: sql entity-framework insert sql-update

我有一个实体集国家,反映了数据库表'<'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();
        }

4 个答案:

答案 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对象具有IdName属性,那么该实现的一个示例可能如下所示:

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();
   }
  }