I am learning about Entity Framework (EF) using code first on version 6+ with C# POCOs. Consider the following example:
public class DatabaseContext : DbContext
{
public virtual DbSet<TextElement> Textuals { get; set; }
}
public class TextElement
{
[Key]
public int Number { get; set; }
public string Content { get; set; }
public virtual ICollection<TextElement> Children { get; set; }
}
What I want to do is to add a new child to an existing parent. in pseudo SQL I could do something like:
INSERT INTO Textuals (Content, ParentId) VALUES ("Lorem Ipsum", 42)
Where 42 is the ID of the parent record.
I've been searching the web for the past day to get EF to do the same for me in C# code. The best I could find is:
using (var context = new DatabaseContext())
{
var parent = new TextElement { Number = 42, Children = new List<TextElement>() };
var child = new TextElement { Content = "I iz kiddo" };
context.Textuals.Attach(parent);
parent.Children.Add(child);
context.SaveChanges();
}
However, the Attach call seems to run a query too. The same issue applies to deleting an entity by id, that needs an Attach as well, running an unnecessary query.
Is there a better performing alternative to do what I want: add a child entity to an existing parent?
Update
Based on cverb's answer I got the following code doing what I want:
public class TextElement
{
[Key]
public int Number { get; set; }
public string Content { get; set; }
public virtual ICollection<TextElement> Children { get; set; }
// Added custom parent id reference, MUST be nullable to allow
// for entries without parent
public int? ParentId { get; set; }
}
Now, because this is a name that breaks convention (convention dictates TextElementId which is as vague as can be) I needed to change the Context with a little "fluent api" code. This explicitly defines the relations between the properties in the class.
public class DatabaseContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<TextElement>()
.HasMany((e) => e.Children) // Indicate the many relation
.WithOptional() // Indicate that the many
// relation is optional.
// Don't require a nav prop
.HasForeignKey((e) => e.ParentId); // The FK to use with the
// relation.
}
public virtual DbSet<TextElement> Textuals { get; set; }
}
Which enables me to successfully apply Migrations as well.
ParentIdproperty in your TextElement entity?Childrenproperty. I obviously like EF to handle the implementation details =). But without performance overhead if possible.