none
EF 4.1 Code First Strange behavior with Parent-Child Relationship RRS feed

  • Question

  • This is an ASP.NET application

     

    I'm not sure what series of events creates this bug but once it gets in this state it's broken.

    This tool is used to Map something called a Rollup to a list of StrengthForms. Rollups come from another system.

     

    var med = db.Rollups.Include(r => r.StrengthForms)
                                   .Include(r => r.StrengthForms.Select(s => s.Form))
                                   .Include(r => r.StrengthForms.Select(s => s.Unit))
                                   .SingleOrDefault(r => r.RollupId == rollupId);
    //web service call removed 
    
    if (med == null)
     {
           med = new MedRollup();
           med.RollupId = rollupId;
           db.Rollups.Add(med);
           med.CreatedDateTime = DateTime.Now;
    }
    
    med.MedName = medName.MedName;
    med.MedNameId = (int)medId.MedNameID;
    db.SaveChanges();



    medName and medId came from a web service. On initial page load I take this opportunity to update the Name.

     

    In the broken state the StrengthForms table in Sql had 7 records with a particular FK:RollupId

     

    med.StrengthForms.Count() returned 6 (after several debug attempts this was then always 5)

    db.StrengthForms.Local.Count() returned 7

    db.StrengthForms.Where(sf=> sf.RollupID == rollupId).Count() returned 7

    select * from StrengthForms where RollupID = xxxx (where xxxx is the rollupID) returned 7 records

     

    db.SaveChanges() causes the error

     

    The operation failed: The relationship could not be changed because one or more of the foreign-key properties 
    is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value.
    If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property
    must be assigned another non-null value, or the unrelated object must be deleted.
    Even though all I've done is load fresh from database update 2 properties and saved.

     

    After this I set some labels and med.StrengthForms.Select to create a custom list using a different type not known by EF for use in my UI. This list is kept in Session so the user can add/edit/delete the StrengthForms. To Save I load a fresh the same as before (without the name update) loop through my temp list and manually update the real list. For Deletes I'm doing db.StrengthForms.Remove.

     

     

    Can anyone explain why I'm seeing this different counts? It looks right in the database but EF doesn't load it right. db.StrengthForms.Local has all the correct records from the database so it is loading them. Somehow DbContext thinks a few should be children of the Rollup. I was able to fix the broken one by loading the list from the sql as db.StrengthForms.Where(sf=> sf.RollupID == rollupId) instead of loading the med and using it's navigation property. DbContext can't be caching anything to cause the problem because the problem was created on our QA server during testing and I could see the problem in the debugger running on my local machine connecting to the QA database. Which makes this really confusing since the database tables appear correct.

     

    OnModelCreating incase this will help.

     

    base.OnModelCreating(modelBuilder);
                modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
                modelBuilder.Entity<MedRollup>().HasKey(r => r.RollupId);
                modelBuilder.Entity<MedRollup>().Property(r => r.RollupId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
                modelBuilder.Entity<MedRollup>().HasMany<StrengthForm>(sf => sf.StrengthForms).WithOptional().HasForeignKey(k => k.RollupId);
                modelBuilder.Entity<StrengthForm>().ToTable("StrengthForms");
                modelBuilder.Entity<StrengthForm>().Property(sf => sf.Strength).HasPrecision(18, 6);
                modelBuilder.Entity<StrengthForm>().HasRequired(s => s.Form).WithMany().HasForeignKey(s => s.DoseFormId).WillCascadeOnDelete(false);
                modelBuilder.Entity<StrengthForm>().HasRequired(s => s.Unit).WithMany().HasForeignKey(s => s.DoseUnitId).WillCascadeOnDelete(false);
    


     

     


    • Edited by skicoder Thursday, November 17, 2011 9:49 PM
    Thursday, November 17, 2011 9:45 PM

Answers

All replies

  • Hi skicoder,

    Welcome!

    The Local property of DbSet provides simple access to the entities of the set that are currently being tracked by the context and have not been marked as Deleted. (http://blogs.msdn.com/b/adonet/archive/2011/02/01/using-dbcontext-in-ef-feature-ctp5-part-7-local-data.aspx)

    I'm not sure how do you update your records? If the med is null, you create a new install, you should set each properties and add to context:

           med = new MedRollup(){StrengthForms= new List<StrengthForm>()};
           med.RollupId = rollupId;
           
           med.CreatedDateTime = DateTime.Now;

           med.StrengthForms.Add(new StrengthForm(){});// add the strengthFrom instance here.

          db.Rollups.Add(med);

          db.SaveChanges();

    For Fluent API:

           Standard one to many:
    modelBuilder.Entity<Product>()
        .HasRequired(p => p.PrimaryCategory)
        .WithMany(c => c.Products)
        .HasForeignKey(p => p.PrimaryCategoryCode);

    http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx

    Have a nice day. 

     


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, November 18, 2011 7:49 AM
    Moderator
  • Hi,

    I am writing to check the status of the issue on your side.  Would you mind letting us know the result of the suggestions?

    If you need further assistance, please feel free to let me know.   I will be more than happy to be of assistance.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, November 23, 2011 1:47 AM
    Moderator