4

(Using Entity Framework 6.2)

I have the following two models/entities:

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

And the following DbContext

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

My question is: If the children of the Country object change (i.e. the Cities), how do I update this?

Can I do this:

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

Would that work? Or should I specifically add each city? i.e.:

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();
}  
8
  • dbContext.Countries.Cities.Clear(); will definitely not work since Countries is a DbSet<Country> which does not have a Cities property ;) Commented Feb 23, 2017 at 9:37
  • Hehe, thanks for the reply Balazs. Not sure if one of us is confused, but doesn't the DbSet<Country> indeed have a Cities property: public virtual ICollection<City> Cities { get; set; } Commented Feb 23, 2017 at 9:39
  • No, not the DbSet but an actual entity, that is, a Country instance is what contains it. Commented Feb 23, 2017 at 9:41
  • Possible duplicate: stackoverflow.com/q/27176014/861716 Commented Feb 23, 2017 at 9:45
  • @user1900799 Are you getting any error with your code or is it simply not adding cities to country ? Commented Feb 23, 2017 at 10:11

1 Answer 1

6

You need to add Cities to that particular Country object which is being updated.

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

Update :

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

Hope it helps.

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks for the reply Venky. I actually had made a mistake in my original post, as pointed out by Balázs. I've updated the post - if you look at my second proposed solution (the one with the loop), would that also not work?
I think First you need to add those cities to dbcontext like dbcontext.cities.add(city) and then you should be able to add them to countries just like you did.
@Venky no, not really, since EF is able to discover changes in associated entities, you do not need to both load it via context and update in the parent collection. In fact, you don't even need to clear the parent's collection. Clearing it only makes sense if you indeed want to actually delete all the entities in the collection and add all new ones.
@Balázs thanks for clarification, But cities are newly added . So i don't think dbcontext will now about these changes. I think atleast we should mark the country entity as modified by context.Entry(country).State = EntityState.Modified before savechanges.
@Venky I know it seems like magic for the first time but in fact, you don't even need to do that. This is because of EF internal workings, but to put it simple, think of it like this: whenever you load an entity with EF, EF will add it to a change tracker. Any change made to the entity will cause EF to register it as dirty and so it will properly (magically) update it when you call SaveChanges. Because the child entites are associated with the same context, they will be tracked too.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.