您的位置:首页 > 其它

(转)【配置关系】—Entity Framework实例详解

2012-11-19 20:25 405 查看
原文地址:http://www.cnblogs.com/nianming/archive/2012/11/12/2767089.html

实体间的关系,简单来说无非就是一对一、一对多、多对多,根据方向性来说又分为双向和单向。Code First在实体关系上有以下约定:

1. 两个实体,如果一个实体包含一个引用属性,另一个实体包含一个集合属性,Code First默认约定它们为一对多关系。
2. 两个实体,如果只有一个实体包含一个导航属性或一个集合属性,Code First也默认约定它们是一对多关系。
3. 两个实体分别包含一个集合属性,Code First默认约定它们为多对多关系。
4. 两个实体分别包含一个引用属性,Code First默认约定它们为一对一关系。
5. 在一对一关系情况下,需要提供给Code First额外的信息,以确定它们的主从关系。
6. 在实体中定义一个外键属性,Code First使用属性是否为空来确定关系是必须还是可选。

一、一对一

在Code First中,一对一关系总是需要配置,因为两个实体都包含有一个引用属性,无法确定它们的主从关系。

配置一对一关系常用的方法:

HasRequired ,HasOptional ,WithOptional ,WithRequiredPrincipal,WithRequiredDependent

下面是用到的类:

1: public class Person
2: {
3:     public int PersonId { get; set; }
4:     public int SocialSecurityNumber { get; set; }
5:     public string FirstName { get; set; }
6:     public string LastName { get; set; }
7:     public byte[] RowVersion { get; set; }
8:     public PersonPhoto Photo { get; set; }
9: }
10:
11: public class PersonPhoto
12: {
13:     public int PersonId { get; set; }
14:     public byte[] Photo { get; set; }
15:     public string Caption { get; set; }
16:     public Person PhotoOf { get; set; }
17: }
18:
19: //配置Person
20: public class PersonConfiguration : EntityTypeConfiguration<Person>
21: {
22:     public PersonConfiguration()
23:     {
24:         //主键
25:         HasKey(t => t.PersonId);
26:         //并发检查
27:         Property(t => t.SocialSecurityNumber).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None).IsConcurrencyToken();
28:         //长度50 不为空
29:         Property(t => t.FirstName).IsRequired().HasMaxLength(50);
30:         //长度50 不为空
31:         Property(t => t.LastName).IsRequired().HasMaxLength(50);
32:         //并发检查
33:         Property(t => t.RowVersion).IsRowVersion();
34:         //HasRequired(t => t.Photo).WithRequiredPrincipal(t => t.PhotoOf);
35:         //HasOptional(t => t.Photo).WithRequired(t => t.PhotoOf);
36:     }
37: }
38:
39: //配置PersonPhoto
40: public class PersonPhotoConfiguration : EntityTypeConfiguration<PersonPhoto>
41: {
42:     public PersonPhotoConfiguration()
43:     {
44:         //主键
45:         HasKey(t => t.PersonId);
46:         //长度50
47:         Property(t => t.Caption).HasMaxLength(50);
48:         //必须从属于Person
49:         HasRequired(t => t.PhotoOf).WithRequiredDependent(t => t.Photo);
50:     }
51: }
52:
53: public class BreakAwayContext : DbContext
54: {
55:     public DbSet<Person> People { get; set; }
56:     public DbSet<PersonPhoto> Photos { get; set; }
57:
58:     protected override void OnModelCreating(DbModelBuilder modelBuilder)
59:     {
60:         modelBuilder.Configurations.Add(new PersonConfiguration());
61:         modelBuilder.Configurations.Add(new PersonPhotoConfiguration());
62:         base.OnModelCreating(modelBuilder);
63:     }
64: }
65:
66: public class Initializer : DropCreateDatabaseAlways<BreakAwayContext>
67: {
68:     public Initializer()
69:     {
70:     }
71:
72:     //创建数据库时 Seed数据
73:     protected override void Seed(BreakAwayContext context)
74:     {
75:         context.People.Add(new Person()
76:         {
77:             FirstName = "E",
78:             LastName = "F",
79:             SocialSecurityNumber = 123456,
80:             Photo = new PersonPhoto()
81:             {
82:                 Caption = "这是照片",
83:                 Photo = new byte[] { }
84:             }
85:         });
86:         context.SaveChanges();
87:     }
88: }
测试程序

1: [TestClass]
2: public class UnitTest1
3: {
4:     [TestMethod]
5:     public void ShouldReturnAPersonWithPhoto()
6:     {
7:         //Arrange
8:         var init = new Initializer();
9:         Person person;
10:       using (var context = new BreakAwayContext())
11:         {
12:             init.InitializeDatabase(context);
13:             //Act
14:             person = context.People.Include(t => t.Photo).FirstOrDefault();
15:         }
16:         //Assert
17:         Assert.IsNotNull(person);
18:       Assert.IsNotNull(person.Photo);
19:     }
20: }
测试结果:





二、一对多

下面是用到的类:

1: public class Blog
2: {
3:     public Blog()
4:     {
5:         Posts = new List<Post>();
6:     }
7:
8:     public int Id { get; set; }
9:     public DateTime Creationdate { get; set; }
10:   public string ShortDescription { get; set; }
11:     public string Title { get; set; }
12:     public List<Post> Posts { get; set; }
13: }
14:
15: public class Post
16: {
17:     public int Id { get; set; }
18:   public string Title { get; set; }
19:     public string Content { get; set; }
20:     public DateTime PostedDate { get; set; }
21:
22:     //Post可以不归属到Blog独立存在,注意这里的外键属性要设置为可空的
23:     public Nullable<int> BlogId { get; set; }
24:     public virtual Blog Blog { get; set; }
25:
26:     public int PrimaryAuthorId { get; set; }
27:     public virtual Author PrimaryAuthor { get; set; }
28:     public Nullable<int> SecondaryAuthorId { get; set; }
29:     public virtual Author SecondaryAuthor { get; set; }
30: }
31:
32: public class Author
33: {
34:     public int Id { get; set; }
35:     public string Name { get; set; }
36:     public string Email { get; set; }
37:     //个人简历
38:   public string Bio { get; set; }
39:
40:     public List<Post> PrimaryAuthorFor { get; set; }
41:     public List<Post> SecondaryAuthorFor { get; set; }
42: }
43:
44: public class BlogConfiguratioin : EntityTypeConfiguration<Blog>
45: {
46:     public BlogConfiguratioin()
47:     {
48:         ToTable("Blogs");
49:         HasKey(t => t.Id);
50:         Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
51:         Property(t => t.Title).IsRequired().HasMaxLength(250);
52:       Property(t => t.Creationdate).HasColumnName("CreationDate").IsRequired();
53:         Property(t => t.ShortDescription).HasColumnType("Text").IsMaxLength().IsOptional().HasColumnName("Description");
54:         //配置Blog和Post的一对多关系,Blog对Post是可选的,外键BlogId,并设置为级联删除
55:         HasMany(t => t.Posts).WithOptional(t => t.Blog).HasForeignKey(t => t.BlogId).WillCascadeOnDelete();
56:     }
57: }
58:
59: public class PostConfiguration : EntityTypeConfiguration<Post>
60: {
61:     public PostConfiguration()
62:     {
63:         ToTable("Posts");
64:         HasKey(t => t.Id);
65:       Property(t => t.Id).HasColumnName("PostId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
66:         Property(t => t.Content).HasColumnName("Body").IsMaxLength();
67:         Property(t => t.PostedDate).HasColumnName("PostedDate");
68:         Property(t => t.Title).HasColumnName("Title").IsMaxLength();
69:         //配置反转属性,集合属性PrimaryAuthorFor匹配PrimaryAuthor
70:         HasRequired(t => t.PrimaryAuthor).WithMany(t => t.PrimaryAuthorFor);
71:       //配置反转属性,集合属性SecondaryAuthorFor匹配SecondaryAuthor
72:         HasOptional(t => t.SecondaryAuthor).WithMany(t => t.SecondaryAuthorFor);
73:     }
74: }
75:
76: public class AuthorConfiguration : EntityTypeConfiguration<Author>
77: {
78:     public AuthorConfiguration()
79:     {
80:         ToTable("Authors");
81:         HasKey(t => t.Id).Property(t => t.Id).HasColumnName("AuthorId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
82:         Property(t => t.Name).IsRequired().HasMaxLength(50);
83:         Property(t => t.Email).IsRequired().HasMaxLength(50);
84:         Property(t => t.Bio).HasMaxLength(1000);
85:     }
86: }
87:
88: public class BreakAwayContext : DbContext
89: {
90:     public DbSet<Blog> Blogs { get; set; }
91:     public DbSet<Post> Posts { get; set; }
92:     public DbSet<Author> Authors { get; set; }
93:
94:     protected override void OnModelCreating(DbModelBuilder modelBuilder)
95:     {
96:         modelBuilder.Configurations.Add(new BlogConfiguratioin());
97:         modelBuilder.Configurations.Add(new PostConfiguration());
98:         modelBuilder.Configurations.Add(new AuthorConfiguration());
99:         base.OnModelCreating(modelBuilder);
100:     }
101: }
102:
103: public class Initializer : DropCreateDatabaseAlways<BreakAwayContext>
104: {
105:     public Initializer()
106:     {
107:     }
108:
109:     protected override void Seed(BreakAwayContext context)
110:     {
111:         var primaryAuthor = new Author()
112:         {
113:             Name = "张三",
114:             Email = "zhangsan@126.com",
115:             Bio = "张三的简历"
116:         };
117:         var secondaryAuthor = new Author()
118:         {
119:             Name = "李四",
120:             Email = "lisi@126.com",
121:             Bio = "李四的简历"
122:         };
123:         var blog = new Blog()
124:         {
125:             Title = "EF",
126:             ShortDescription = "关于EF的博客",
127:             Creationdate = DateTime.Now
128:         };
129:         blog.Posts.Add(new Post()
130:         {
131:             Title = "配置关系",
132:             PostedDate = DateTime.Now,
133:             Content = "这是Post的内容",
134:             PrimaryAuthor = primaryAuthor,
135:             SecondaryAuthor = secondaryAuthor
136:         });
137:         context.Blogs.Add(blog);
138:         context.SaveChanges();
139:     }
140: }
测试程序:

1: [TestClass]
2: public class OneToManyTest
3: {
4:     [TestMethod]
5:     public void ShouldReturnBlogWithPosts()
6:     {
7:       //Arrage
8:         Database.SetInitializer(new Initializer());
9:         var context = new BreakAwayContext();
10:       //Act
11:         var blog = context.Blogs.Include(t => t.Posts).FirstOrDefault();
12:         //Assert
13:         Assert.IsNotNull(blog);
14:       Assert.IsNotNull(blog.Posts);
15:         Assert.IsNotNull(blog.Posts.FirstOrDefault().PrimaryAuthor);
16:     }
17: }
测试结果:





三、多对多

下面是配置多对多关系用到的类,跟一对多差不多,只不过Post和Author的关系变成多对多的了。

1: public class Post
2: {
3:     public Post()
4:     {
5:         Authors = new List<Author>();
6:     }
7:
8:     public int Id { get; set; }
9:     public string Title { get; set; }
10:   public string Content { get; set; }
11:     public DateTime PostedDate { get; set; }
12:
13:     public virtual List<Author> Authors { get; set; }
14: }
15:
16: public class Author
17: {
18:   public Author()
19:     {
20:         Posts = new List<Post>();
21:   }
22:
23:     public int Id { get; set; }
24:     public string Name { get; set; }
25:   public string Email { get; set; }
26:     //个人简历
27:     public string Bio { get; set; }
28:
29:     public virtual List<Post> Posts { get; set; }
30: }
31:
32: public class PostConfiguration : EntityTypeConfiguration<Post>
33: {
34:     public PostConfiguration()
35:     {
36:         ToTable("Posts");
37:         HasKey(t => t.Id);
38:       Property(t => t.Id).HasColumnName("PostId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
39:       Property(t => t.Content).HasColumnName("Body").IsMaxLength();
40:         Property(t => t.PostedDate).HasColumnName("PostedDate");
41:         Property(t => t.Title).HasColumnName("Title").IsMaxLength();
42:         //配置多对多关系 ToTable 配置生成的关联表名字 MapLeftKey默认表示调用HasMany的实体的主键
43:       //本例中如果不使用MapLeftKey默认生成Post_Id
44:         HasMany(t => t.Authors).WithMany(t => t.Posts).Map(m =>
45:             {
46:                 m.ToTable("PostAuthor");
47:                 m.MapLeftKey("PostId");
48:                 m.MapRightKey("AuthorId");
49:             });
50:     }
51: }
52:
53: public class AuthorConfiguration : EntityTypeConfiguration<Author>
54: {
55:     public AuthorConfiguration()
56:     {
57:       ToTable("Authors");
58:       HasKey(t => t.Id);
59:         Property(t => t.Id).HasColumnName("AuthorId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
60:         Property(t => t.Bio).HasColumnType("Text").IsMaxLength();
61:         Property(t => t.Email).HasMaxLength(100).IsRequired();
62:         Property(t => t.Name).HasMaxLength(100).IsRequired();
63:     }
64: }
65:
66: public class TestContext : DbContext
67: {
68:     public DbSet<Post> Posts { get; set; }
69:     public DbSet<Author> Authors { get; set; }
70:
71:   protected override void OnModelCreating(DbModelBuilder modelBuilder)
72:     {
73:         modelBuilder.Configurations.Add(new PostConfiguration());
74:         modelBuilder.Configurations.Add(new AuthorConfiguration());
75:       base.OnModelCreating(modelBuilder);
76:     }
77: }
78:
79: public class Initializer : DropCreateDatabaseAlways<TestContext>
80: {
81:     protected override void Seed(TestContext context)
82:     {
83:         var post = new Post()
84:         {
85:             Title = "Post1",
86:             Content = "Content1",
87:           PostedDate = DateTime.Now
88:         };
89:         var author = new Author()
90:         {
91:             Name = "张三",
92:             Email = "zhangsan@126.com",
93:           Bio = "张三的简历"
94:         };
95:         var author1 = new Author()
96:         {
97:             Name = "李四",
98:             Email = "lisi@126.com",
99:             Bio = "李四的简历"
100:         };
101:         var author2 = new Author()
102:       {
103:             Name = "王五",
104:             Email = "wangwu@126.com",
105:             Bio = "王五的简历"
106:         };
107:         post.Authors.Add(author);
108:       post.Authors.Add(author1);
109:         context.Posts.Add(post);
110:         post = new Post()
111:         {
112:             Title = "Post2",
113:             Content = "Content2",
114:             PostedDate = DateTime.Now
115:         };
116:         post.Authors.Add(author);
117:         post.Authors.Add(author2);
118:         context.Posts.Add(post);
119:         context.SaveChanges();
120:     }
121: }
测试程序:

1: [TestClass]
2: public class ManyToManyTest
3: {
4:     [TestMethod]
5:     public void ShouldReturnPostWithAuthors()
6:     {
7:       //Arrage
8:         var init = new Initializer();
9:         var context = new ManyToMany.TestContext();
10:       init.InitializeDatabase(context);
11:         //Act
12:       var post = context.Posts.Include(t => t.Authors).FirstOrDefault();
13:         //Assert
14:       Assert.IsNotNull(post);
15:       Assert.AreEqual(2, post.Authors.Count);
16:         Assert.AreEqual("李四", post.Authors[1].Name);
17:     }
18: }
测试结果:





现在关联表中只有两个字段,如下图所示:





如果再加个字段,比如DateAdd,这就需要给关联表定义一个实体。

1: public class Post
2: {
3:     public Post()
4:     {
5:         PostAuthors = new List<PostAuthor>();
6:     }
7:
8:     public int Id { get; set; }
9:     public string Title { get; set; }
10:   public string Content { get; set; }
11:     public DateTime PostedDate { get; set; }
12:
13:     //public virtual List<Author> Authors { get; set; }
14:   public virtual List<PostAuthor> PostAuthors { get; set; }
15: }
16:
17: public class Author
18: {
19:     public Author()
20:     {
21:       PostAuthors = new List<PostAuthor>();
22:   }
23:
24:     public int Id { get; set; }
25:   public string Name { get; set; }
26:     public string Email { get; set; }
27:     //个人简历
28:   public string Bio { get; set; }
29:
30:     //public virtual List<Post> Posts { get; set; }
31:   public virtual List<PostAuthor> PostAuthors { get; set; }
32: }
33:
34: //关联表的实体
35: public class PostAuthor
36: {
37:     public int PostId { get; set; }
38:   public int AuthorId { get; set; }
39:
40:     public Post Post { get; set; }
41:     public Author Author { get; set; }
42:
43:   public DateTime? DateAdd { get; set; }
44: }
45:
46: public class PostConfiguration : EntityTypeConfiguration<Post>
47: {
48:     public PostConfiguration()
49:     {
50:         ToTable("Posts");
51:         HasKey(t => t.Id);
52:       Property(t => t.Id).HasColumnName("PostId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
53:         Property(t => t.Content).HasColumnName("Body").IsMaxLength();
54:         Property(t => t.PostedDate).HasColumnName("PostedDate");
55:         Property(t => t.Title).HasColumnName("Title").IsMaxLength();
56:     }
57: }
58:
59: public class AuthorConfiguration : EntityTypeConfiguration<Author>
60: {
61:     public AuthorConfiguration()
62:     {
63:         ToTable("Authors");
64:         HasKey(t => t.Id);
65:       Property(t => t.Id).HasColumnName("AuthorId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
66:         Property(t => t.Bio).HasColumnType("Text").IsMaxLength();
67:         Property(t => t.Email).HasMaxLength(100).IsRequired();
68:         Property(t => t.Name).HasMaxLength(100).IsRequired();
69:     }
70: }
71:
72: //配置关联表实体
73: public class PostAuthorConfiguration : EntityTypeConfiguration<PostAuthor>
74: {
75:   public PostAuthorConfiguration()
76:     {
77:         ToTable("PostAuthors");
78:       //配置组合主键
79:         HasKey(t => new { t.PostId, t.AuthorId });
80:         Property(t => t.PostId).HasColumnOrder(0);
81:         Property(t => t.AuthorId).HasColumnOrder(1);
82:         //这里是配置一对多关系
83:         HasRequired(t => t.Post).WithMany(t => t.PostAuthors).HasForeignKey(t => t.PostId);
84:         HasRequired(t => t.Author).WithMany(t => t.PostAuthors).HasForeignKey(t => t.AuthorId);
85:     }
86: }
87:
88: public class TestContext : DbContext
89: {
90:     public DbSet<Post> Posts { get; set; }
91:     public DbSet<Author> Authors { get; set; }
92:     public DbSet<PostAuthor> PostAuthors { get; set; }
93:
94:     protected override void OnModelCreating(DbModelBuilder modelBuilder)
95:     {
96:         modelBuilder.Configurations.Add(new PostConfiguration());
97:         modelBuilder.Configurations.Add(new AuthorConfiguration());
98:         modelBuilder.Configurations.Add(new PostAuthorConfiguration());
99:         base.OnModelCreating(modelBuilder);
100:     }
101: }
102:
103: public class Initializer : DropCreateDatabaseAlways<TestContext>
104: {
105:     protected override void Seed(TestContext context)
106:     {
107:         var post = new Post()
108:       {
109:             Title = "Post1",
110:             Content = "Content1",
111:             PostedDate = DateTime.Now
112:         };
113:         post = context.Posts.Add(post);
114:         var author = new Author()
115:         {
116:             Name = "张三",
117:             Email = "zhangsan@126.com",
118:             Bio = "张三的简历"
119:         };
120:         var author1 = new Author()
121:         {
122:             Name = "李四",
123:             Email = "lisi@126.com",
124:             Bio = "李四的简历"
125:         };
126:         author = context.Authors.Add(author);
127:         author1 = context.Authors.Add(author1);
128:         context.SaveChanges();
129:         PostAuthor pa1 = new PostAuthor()
130:         {
131:             PostId = post.Id,
132:             AuthorId = author.Id,
133:             DateAdd = DateTime.Now
134:         };
135:         PostAuthor pa2 = new PostAuthor()
136:         {
137:             PostId = post.Id,
138:             AuthorId = author1.Id,
139:             DateAdd = DateTime.Now
140:         };
141:         context.PostAuthors.Add(pa1);
142:         context.PostAuthors.Add(pa2);
143:         context.SaveChanges();
144:     }
145: }
测试程序:

1: [TestMethod]
2: public void ShouldReturnAuthorsWithDateAdd()
3: {
4:     //Arrage
5:     var init = new Initializer();
6:     var context = new ManyToMany.TestContext();
7:   init.InitializeDatabase(context);
8:     //Act
9:     var post = context.Posts.Include(t => t.PostAuthors).FirstOrDefault();
10:   //Assert
11:     Assert.IsNotNull(post);
12:   Assert.AreEqual(2, post.PostAuthors.Count);
13:     Assert.IsNotNull(post.PostAuthors[0].DateAdd);
14: }
测试结果:





生成的关联表如下图所示:





四、结束语

点击查看《Entity Framework实例详解》系列的其他文章。

如果遇到问题,可以加群:276721846 进行讨论。

另外欢迎大家访问Entity Framework社区,网址是www.ef-community.comwww.ef-community.cn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: