[英]Specify the name of a parent-child join table using EF6 Code-First EntityTypeConfiguration
[英]how to annotate a parent-child relationship with Code-First
当使用实体框架代码优先库的CTP 5(如宣布在这里)我试图创建一个映射到一个非常简单的层次结构表中的类。
这是构建表的 SQL:
CREATE TABLE [dbo].[People]
(
Id uniqueidentifier not null primary key rowguidcol,
Name nvarchar(50) not null,
Parent uniqueidentifier null
)
ALTER TABLE [dbo].[People]
ADD CONSTRAINT [ParentOfPerson]
FOREIGN KEY (Parent)
REFERENCES People (Id)
这是我希望自动映射回该表的代码:
class Person
{
public Guid Id { get; set; }
public String Name { get; set; }
public virtual Person Parent { get; set; }
public virtual ICollection<Person> Children { get; set; }
}
class FamilyContext : DbContext
{
public DbSet<Person> People { get; set; }
}
我在 app.config 文件中设置了连接字符串,如下所示:
<configuration>
<connectionStrings>
<add name="FamilyContext" connectionString="server=(local); database=CodeFirstTrial; trusted_connection=true" providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>
最后,我尝试使用该类添加父实体和子实体,如下所示:
static void Main(string[] args)
{
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(fred);
var rowCount = context.SaveChanges();
Console.WriteLine("rows added: {0}", rowCount);
var population = from p in context.People select new { p.Name };
foreach (var person in population)
Console.WriteLine(person);
}
}
这里显然缺少一些东西。 我得到的例外是:
列名“PersonId”无效。
我理解约定优于配置的价值,我和我的团队对抛弃 edmx / 设计师噩梦的前景感到兴奋——但似乎没有关于约定是什么的明确文件。 (我们只是幸运地想到了复数表名的概念,对于单数类名)
关于如何使这个非常简单的例子落到位的一些指导将不胜感激。
更新:将 People 表中的列名从 Parent 更改为 PersonId 允许继续添加fred
。 Howerver你会发现, pebbles
是加入的儿童收集fred
,所以我本来期望加入弗雷德鹅卵石时要添加到数据库中为好,但这种情况并非如此。 这是一个非常简单的模型,因此我对将几行输入数据库中涉及这么多猜测工作感到非常沮丧。
您需要使用 fluent API 来实现您想要的模式(数据注释不会这样做)。 确切地说,您有一个Independent One-to-Many Self Reference Association
,该Independent One-to-Many Self Reference Association
还具有外键列 (People.Parent) 的自定义名称。 以下是使用 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"));
}
但是,这会引发InvalidOperationException
并带有此消息Sequence contains more than one matching element 。 根据史蒂文在他的回答中提到的链接,这听起来是一个 CTP5 错误。
在 RTM 中修复此错误之前,您可以使用一种解决方法,即接受 FK 列的默认名称PersonID
。 为此,您需要稍微更改架构:
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
然后使用这个 fluent API 将您的数据模型与 DB Schema 匹配:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOptional(p => p.Parent)
.WithMany(p => p.Children)
.IsIndependent();
}
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();
}
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();
}
这两个代码具有相同的效果,即添加一个新的父级 (Fred) 和一个子级 (Pebbles)。
在 Entity Framework 6 中你可以这样做,注意public Guid? ParentId { get; set; }
public Guid? ParentId { get; set; }
public Guid? ParentId { get; set; }
. 外键必须可以为空才能工作。
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; }
}
它应该使用如下映射来工作:
class FamilyContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Person>().HasMany(x => x.Children).WithMany().Map(y =>
{
y.MapLeftKey((x => x.Id), "ParentID");
y.MapRightKey((x => x.Id), "ChildID");
});
}
}
但是,这会引发异常:序列包含多个匹配元素。 显然这是一个错误。
请参阅此线程和@shichao 问题的答案: http : //blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx#10102970
class Person
{
[key()]
public Guid Id { get; set; }
public String Name { get; set; }
[ForeignKey("Children")]
public int? PersonId {get; set;} //Add ForeignKey
public virtual Person Parent { get; set; }
public virtual ICollection<Person> Children { get; set; }
}
builder.Entity<Menu>().HasMany(m => m.Children)
.WithOne(m => m.Parent)
.HasForeignKey(m => m.PersonId);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.