how to annotate a parent-child relationship with Code-First
In Entity Framework 6 you can do it like this, note public Guid? ParentId { get; set; }
. The foreign key MUST be nullable for it to work.
class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid? ParentId { get; set; }
public virtual Person Parent { get; set; }
public virtual ICollection<Person> Children { get; set; }
}
https://stackoverflow.com/a/5668835/3850405
You need to drop down to fluent API to achieve your desired schema (Data annotations wouldn't do it). Precisely you have an Independent One-to-Many Self Reference Association
that also has a custom name for the foreign key column (People.Parent). Here is how it supposed to get done with EF Code First:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOptional(p => p.Parent)
.WithMany(p => p.Children)
.IsIndependent()
.Map(m => m.MapKey(p => p.Id, "ParentID"));
}
However, this throws an InvalidOperationException
with this message Sequence contains more than one matching element. which sounds to be a CTP5 bug as per the link Steven mentioned in his answer.
You can use a workaround until this bug get fixed in the RTM and that is to accept the default name for the FK column which is PersonID
. For this you need to change your schema a little bit:
CREATE TABLE [dbo].[People]
(
Id uniqueidentifier not null primary key rowguidcol,
Name nvarchar(50) not null,
PersonId uniqueidentifier null
)
ALTER TABLE [dbo].[People] ADD CONSTRAINT [ParentOfPerson]
FOREIGN KEY (PersonId) REFERENCES People (Id)
GO
ALTER TABLE [dbo].[People] CHECK CONSTRAINT [ParentOfPerson]
GO
And then using this fluent API will match your data model to the DB Schema:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOptional(p => p.Parent)
.WithMany(p => p.Children)
.IsIndependent();
}
Add a new Parent record containing a Child:
using (FamilyContext context = new FamilyContext())
{
var pebbles = new Person
{
Id = Guid.NewGuid(),
Name = "Pebbles",
};
var fred = new Person
{
Id = Guid.NewGuid(),
Name = "Fred",
Children = new List<Person>()
{
pebbles
}
};
context.People.Add(fred);
context.SaveChanges();
}
Add a new Child record containing a Parent:
using (FamilyContext context = new FamilyContext())
{
var fred = new Person
{
Id = Guid.NewGuid(),
Name = "Fred",
};
var pebbles = new Person
{
Id = Guid.NewGuid(),
Name = "Pebbles",
Parent = fred
};
context.People.Add(pebbles);
var rowCount = context.SaveChanges();
}
Both codes has the same effect and that is adding a new parent (Fred) with a child (Pebbles).