在Entity Framework 6中更新子对象

4
(使用Entity Framework 6.2)
我有以下两个模型/实体:

public class City
    {
        public int CityId { get; set; }
        public string Name { get; set; }
    }

public class Country
    {
        public Country()
        {
            Cities new HashSet<City>();
        }

        public int CountryId { get; set; }
        public string Name { get; set; }
        public virtual ICollection<City> Cities { get; set; }
    }   

以下是DbContext

public DbSet<Country> Countries { get; set; }

我的问题是:如果Country对象的子项(即城市)发生变化,我该如何更新?

我可以这样做吗:

List<City> cities = new List<City>();
// Add a couple of cities to the list...
Country country = dbContext.Countries.FirstOrDefault(c => c.CountryId == 123);
if (country != null)
{
    country.Cities.Clear();
    country.Cities = cities;
    dbContext.SaveChanges();
}

那样可以吗?还是我需要具体添加每个城市?例如:
List<City> cities = new List<City>();
// Add a couple of cities to the list...
Country country = dbContext.Countries.FirstOrDefault(c => c.CountryId == 123);
if (country != null)
{
    country.Cities.Clear();
    foreach (City city in cities)
        country.Cities.Add(city);
    dbContext.SaveChanges();
}  

dbContext.Countries.Cities.Clear(); 绝对行不通,因为 Countries 是一个 DbSet<Country>,它没有 Cities 属性 ;) - Balázs
呵呵,谢谢你的回复Balazs。不确定我们中的哪一个混淆了,但是DbSet<Country>确实有一个Cities属性: public virtual ICollection<City> Cities { get; set; } - Fabricio Rodriguez
可能是重复问题:https://dev59.com/RV4d5IYBdhLWcg3wG_WH - Gert Arnold
@user1900799 是否 country.Cities = cities; 或者 foreach (City city in cities) country.Cities.Add(city); 有起作用吗?我认为你正在寻找 AddRange(),如 countries.Cities.AddRange(cities),但我不确定这是否是你所询问的。 - kimbaudi
AddRange()会很好,但不幸的是只有Add()方法可用... - Fabricio Rodriguez
显示剩余3条评论
1个回答

6

您需要将Cities添加到正在更新的特定Country对象中。

public Country Update(Country country)
{
    using (var dbContext =new DbContext())
    {
        var countryToUpdate = dbContext.Countries.SingleOrDefault(c => c.Id == country.Id);
        countryToUpdate.Cities.Clear();
        foreach (var city in country.Cities)
        {
            var existingCity =
                dbContext.Cities.SingleOrDefault(
                    t => t.Id.Equals(city.cityId)) ??
                dbContext.Cities.Add(new City
                {
                    Id = city.Id,
                    Name=city.Name
                });

            countryToUpdate.Cities.Add(existingCity);
        }
        dbContext.SaveChanges();
        return countryToUpdate;
    }
}

更新:

  public class City
    {
        public int CityId { get; set; }
        public string Name { get; set; }

        [ForeignKey("Country")]
        public int CountryId {get;set;}
        public virtual Country Country {get; set;}
    } 

希望这能有所帮助。

谢谢您的回复,Venky。实际上我在原帖中犯了一个错误,正如Balázs所指出的那样。我已经更新了帖子 - 如果您看一下我的第二个提议解决方案(循环的那个),那也不行吗? - Fabricio Rodriguez
我认为首先你需要像 dbcontext.cities.add(city) 一样将这些城市添加到 dbcontext 中,然后你就可以像之前添加国家一样将它们添加到 countries 中了。 - Venkata Dorisala
@Venky 不用,因为EF能够发现关联实体的更改,所以您不需要通过上下文加载它并在父集合中更新。事实上,您甚至不需要清除父级集合。只有在确实要删除集合中的所有实体并添加所有新实体时,才有必要清除它。 - Balázs
@Balázs感谢您的澄清,但是城市是新添加的。因此,我认为dbcontext不会知道这些更改。在保存更改之前,我认为至少我们应该将国家实体标记为已修改context.Entry(country).State = EntityState.Modified - Venkata Dorisala
@Venky 我知道这对于第一次来说似乎像是魔法,但事实上,你甚至不需要那样做。这是因为EF的内部工作原理,但简单来说,就像这样:每当你用EF加载实体时,EF会将其添加到更改跟踪器中。对实体所做的任何更改都会使EF将其注册为脏数据,因此在调用 SaveChanges 时它就会正确地(神奇地)更新它。由于子实体与同一个上下文关联,它们也将被跟踪。 - Balázs
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接