0

I have added a prop to my class and added a new DbSet but when saving, it does not store my child objects. My house class:

[Table("Houses")]
public class House
{
    [Key]
    public int ID { get; set; }
    public List<Price> Prices { get; set; } // <-- new prop
}

my dbcontext has a Prices prop now: public DbSet<Price> Prices { get; set; } and I enabled migrations, added the migration and updated the database. So the prices table is created.

When I update a House object, it does not insert anything in the Prices table.

var h = new House(); // with prices etc filled
if (db.Houses.Any(hc => hc.Code.Equals(h.Code, StringComparison.InvariantCultureIgnoreCase)))
{
    var original = db.Houses.First(k => k.Code.Equals(h.Code, StringComparison.InvariantCultureIgnoreCase));
    h.ID = original.ID; // workaround for The property 'ID' is part of the object's key information and cannot be modified.
    h.CountryId = original.CountryId;

    db.Entry(original).CurrentValues.SetValues(h);
    db.SaveChanges(); // does update House fields, but no prices
} else { // add new 
    db.Houses.Add(h);
    db.SaveChanges();
}

I did add public virtual House House { get; set; } to my Price class. But I do not fill it, because when populating the house object, I do not know the ID in the db yet. Maybe that is causing it? I have also read https://stackoverflow.com/a/26572122/169714 and added this to my Price class:

[ForeignKey("HouseId")]
public virtual House House { get; set; }
public int HouseId { get; set; }

but still no entries in the prices table. I am probably doing something wrong storing/updating the database.

edit current store method:

using (var db = new MyCommon.HouseContext()) 
{
    var l = db.Countries.First(tmpC => tmpC.Code.Equals(h.Country.Code));
    h.OperatorId = op.ID;
    h.CountryId = l.ID;
    h.Country = l;

    var existingHouse = db.Houses.Where(p => p.Code.Equals(h.Code, StringComparison.InvariantCultureIgnoreCase)).SingleOrDefault();

    if (existingHouse != null)
    {
        // update
        h.ID = existingHouse.ID; // workaround for The property 'ID' is part of the object's key information and cannot be modified.
        h.CountryId = existingHouse.CountryId;
        h.OperatorId = existingHouse.OperatorId;

        db.Entry(existingHouse).CurrentValues.SetValues(h);
        db.Entry(existingHouse).State = System.Data.Entity.EntityState.Modified;
        //db.SaveChanges(); // moved to bottom for perf. 
    }
    else
    {
        existingHouse = h;
        db.Houses.Add(h);            // insert
    }

    foreach (var ft in existingHouse.Prices)
    {
        var existingFt = existingHouse.Prices.SingleOrDefault(f => f.ID == ft.ID);

        if (existingFt != null)
        {
            db.Entry(existingFt).CurrentValues.SetValues(ft);
            db.Entry(existingFt).State = System.Data.Entity.EntityState.Modified;
        }
        else
        {
            existingHouse.Prices.Add(ft);
        }
    }
    db.SaveChanges();
}
JP Hellemons
  • 5,977
  • 11
  • 63
  • 128
  • You're updating a House object, but at what point do you make any changes to Prices that need to be updated? It should be handled automatically, but it's hard to say because you omitted that part. – C. Helling Jun 29 '17 at 14:34
  • indeed, but it's before the `if`. I fill the `Prices` there. Debugger shows that h.Prices has over 100 objects in it. Db table stays empty. – JP Hellemons Jun 29 '17 at 14:38
  • Do you mark their `EntityState.Modified` (Or `Added`)? – C. Helling Jun 29 '17 at 14:44
  • I'm a bit confused on the difference between "Prices" and "Features." Your House object has a List, but when you loop through these, you add them to `existingHouse.Features` instead? – C. Helling Jun 30 '17 at 14:47
  • sorry, bad paste. It's `Prices`. but still does not store child objects. – JP Hellemons Jun 30 '17 at 14:57
  • It's hard to say without being able to debug it myself, but perhaps try this: https://stackoverflow.com/questions/27176014/how-to-add-update-child-entities-when-updating-a-parent-entity-in-ef He removes the child objects first before re-adding them later. – C. Helling Jun 30 '17 at 15:03

1 Answers1

0

Check the EntityState of your objects. Attach the object to your context, and iterate through these Prices to mark the EntityState.Modified. If the Price objects are new, you can use EntityState.Added. You can see here for an 'upsert' pattern example.

C. Helling
  • 1,394
  • 6
  • 20
  • 34
  • I am looking into https://stackoverflow.com/a/27177623/169714 and am combining it with your answer. The MSDN link is really helpful. Will let you know if it's fixed! Thanks! – JP Hellemons Jun 30 '17 at 08:15
  • I have read the msdn article and the SO question I posted in the previous comment. combined with https://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework?rq=1 I thought that my edited question should work. because the house object is tracked and the childs should therefor also be tracked and inserted/updated. but no rows touched or inserted in the db. I am missing something... – JP Hellemons Jun 30 '17 at 14:39