2

EDIT Better isolated the error; see below.

I have a ParentObject and ChildObject class in a C# Code-First EF model:

public class ParentObject{
    [Key]
    public int Key{get; set;}
    [Required]
    public string Name {get; set;} //unique identifier
    public HashSet<ChildObject> TheChildren {get; set;}
}

public class ChildObject{
    [Key]
    public int Key {get; set;}
    public int ParentKey {get; set;}
    public string Name {get; set;}
    [NotMapped]
    string ParentName {get; set;}
}

 public class FamilyDB : DbContext{
    public DbSet<ParentObject> Parents { get; set; } 
    public DbSet<ChildObject> Children { get; set; }

    public FamilyDB(): base(){
        this.Parents.Load(); this.Children.Load();
    }
}

I'd like to populate a FamilyDB database from a set of CSV files. The Parents already exist; I just need to overwrite and assign TheChildren for each ParentObject.

But I always end up with an error:

public static void ImportChildFile(FamilyDB connxn, string csvPath){
    List<ChildObject> records = GetChildrenFromCsvFile(csvPath);
    var groupedRecords = records.GroupBy(x => x.ParentName);

    foreach (var recordSet in groupedRecords){
        parentName = recordSet.Key;
        ParentObject matchingParent = connxn.Parents.
            Where(x => x.Name = parentName).FirstOrDefault();

        if (matchingParent == null)
            throw new ArgumentException("No prnt named " + parentName);

        //Want to overwrite, not add - must remove all current children
        while (matchingParent.Children.Count > 0)
            connxn.TheChildren.Remove(matchingParent.Children.Last());

        matchingParent.TheChildren.UnionWith(recordSet);
        //connxn.SaveChanges(); //this would work if it was here
    }
    connxn.SaveChanges();

    /*Multiplicity constraint violated. 
    The role 'ParentObject_Children_Source' of 
    the relationship 'MyNamespace.ParentObject_Children' 
    has multiplicity 1 or 0..1.*/
}

That error message seems to accuse me of assigning to the same ParentObject twice, but I did no such thing, as each recordSet corresponds to a different ParentName (and thus parent.) So what is going on?

UiUx
  • 967
  • 2
  • 14
  • 25
Arithmomaniac
  • 4,604
  • 3
  • 38
  • 58
  • Have you tried replacing all your custom methods (`FindFirstByName`, `UnionWith`) by native ones? Have you tried using `List` instead of `HashSet`? Why are you removing children from context and not from navigation property? And I'd like to see mapping attributes. – Sergei Rogovtcev Jul 25 '12 at 19:45
  • 1) Yes; `UnionWith` is native, and I just unwound `FindFirstByName` for display. 2) Yes. 3) I'm an EF newbie; I don't quite get that difference, or what you propose to do instead. Have a link? 4) Updated. – Arithmomaniac Jul 25 '12 at 20:32
  • 1
    Looks OK to me. `ParentKey` would not be detected as foreign key property with that name (or do you have mapping with Fluent API?), but I don't see why this should matter. Do you get this error *always*, even with only 2 `groupedRecords`? Do you get the error also when you don't load the entities in the context constructor? Also I'm wondering why you query the DB again although you have loaded everything into memory first... – Slauma Jul 25 '12 at 20:42
  • It seems to me that EF can't detect how to navigate/store `Parent` for `ChildObject`. Try annotating `TheChildren` with `[ForeignKey("ParentKey")]`. – Sergei Rogovtcev Jul 26 '12 at 06:19
  • @SergRogovtsev: That annotation would be invalid. You can't use an annotation at all for this because there is no navigation property in `ChildObject` refering to the parent. Either the `ParentKey` follows naming conventions (which it doesn't in the example above, but who knows, these are obviously not the real model names) or you must configure it with Fluent API: `modelBuilder.Entity().HasMany(p => p.TheChildren).WithRequired().HasForeignKey(c => c.ParentKey);` – Slauma Jul 26 '12 at 10:57
  • 1
    @Slauma "Programming Entity Framework: Core First", "Working with Relationships that Have Unidirectional Navigation", p.84: "But we no longer have a navigation property in the dependent class. Fortunately, *we can just place* the data annotation on the navigation property we do have (`Destination.Lodgings`). Code First knows that `Lodging` is the dependent in the relationship, so it will search in that class for the foreign key: `[ForeignKey("LocationId")] public List Lodgings { get; set; }` The Fluent API *also* caters to relationships that only have one navigation property." – Sergei Rogovtcev Jul 26 '12 at 14:30
  • @SergRogovtsev: Awesome! Thanks for that info, I could have bet it wouldn't work. Always something new to learn... – Slauma Jul 26 '12 at 14:52
  • I'd recommend this book (along with its companion "Programming Entity Framework: DbContext") to anyone working with EF/CF. Worthless. – Sergei Rogovtcev Jul 26 '12 at 15:06

0 Answers0