实体间的关系,简单来说无非就是一对一、一对多、多对多,根据方向性来说又分为双向和单向。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. 1: public class Person
  1. 2: {
  1. 3: public int PersonId { get; set; }
  1. 4: public int SocialSecurityNumber { get; set; }
  1. 5: public string FirstName { get; set; }
  1. 6: public string LastName { get; set; }
  1. 7: public byte[] RowVersion { get; set; }
  1. 8: public PersonPhoto Photo { get; set; }
  1. 9: }
  1. 10:  
  1. 11: public class PersonPhoto
  1. 12: {
  1. 13: public int PersonId { get; set; }
  1. 14: public byte[] Photo { get; set; }
  1. 15: public string Caption { get; set; }
  1. 16: public Person PhotoOf { get; set; }
  1. 17: }

因为Photo是具体人的,所以PersonPhoto使用PersonId作为主键。

下面是一对一关系配置的几种情况:

1.PersonPhoto必须属于一个Person,但是Person不一定有PersonPhoto,这种关系是1:0..1,此种情况下Person是一定存在的,所以它是主从关系主的一方。

  1. 1: HasRequired(t => t.PhotoOf).WithOptional(t => t.Photo);

  1. 1: HasOptional(t => t.Photo).WithRequired(t => t.PhotoOf);

2.PersonPhoto必须属于一个Person,Person也必须有PersonPhoto,这种关系式1:1,此种情况下,两个都一定存在,要确定主从关系,需要使用WithRequiredPrincipal或WithRequiredDependent。

  1. 1: HasRequired(t => t.PhotoOf).WithRequiredDependent(t => t.Photo);

  1. 1: HasRequired(t => t.Photo).WithRequiredPrincipal(t => t.PhotoOf);

上述两种情况都是真实存在的,不真实存在的就不说了。

下面配置一对一关系贴出Demo:

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

测试程序

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

测试结果:

二、一对多

下面是用到的类:

  1. 1: public class Blog
  1. 2: {
  1. 3: public Blog()
  1. 4: {
  1. 5: Posts = new List<Post>();
  1. 6: }
  1. 7:  
  1. 8: public int Id { get; set; }
  1. 9: public DateTime Creationdate { get; set; }
  1. 10: public string ShortDescription { get; set; }
  1. 11: public string Title { get; set; }
  1. 12: public List<Post> Posts { get; set; }
  1. 13: }
  1. 14:  
  1. 15: public class Post
  1. 16: {
  1. 17: public int Id { get; set; }
  1. 18: public string Title { get; set; }
  1. 19: public string Content { get; set; }
  1. 20: public DateTime PostedDate { get; set; }
  1. 21:  
  1. 22: public Nullable<int> BlogId { get; set; }
  1. 23: public virtual Blog Blog { get; set; }
  1. 24:  
  1. 25: public int PrimaryAuthorId { get; set; }
  1. 26: public virtual Author PrimaryAuthor { get; set; }
  1. 27: public Nullable<int> SecondaryAuthorId { get; set; }
  1. 28: public virtual Author SecondaryAuthor { get; set; }
  1. 29: }
  1. 30:  
  1. 31: public class Author
  1. 32: {
  1. 33: public int Id { get; set; }
  1. 34: public string Name { get; set; }
  1. 35: public string Email { get; set; }
  1. 36: //个人简历
  1. 37: public string Bio { get; set; }
  1. 38:  
  1. 39: public List<Post> PrimaryAuthorFor { get; set; }
  1. 40: public List<Post> SecondaryAuthorFor { get; set; }
  1. 41: }

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

HasOptional ,HasRequired ,HasMany

Has方法后面往往跟着With方法

WithOptional ,WithRequired ,WithMany

下面配置一对多的几种情况:

1.Post一定归属于一个Blog,这种关系是1:n。

  1. 1: HasMany(x => x.Posts).WithRequired(x =>x.Blog)

  1. 1: HasRequired(x => x.Blog).WithMany(x => x.Posts)

2.Post可以单独存在,不用归属于Blog,这种关系是0..1:n。

  1. 1: HasMany(x => x.Posts).WithOptional(x => x.Blog)

  1. 1: HasOptional(x => x.Blog).WithMany(x => x.Posts)

设置外键

外键的默认约定:

[Target Type Key Name], [Target Type Name] + [Target Type Key Name], or [Navigation 
Property Name] + [Target Type Key Name]

本例中,匹配的是[Target Type Name] + [Target Type Key Name],目标类型是Blog,目标类型主键是Id,加起来就是BlogId。下面使用Fluent API显示设置外键:

  1. 1: HasMany(x => x.Posts).WithOptional(x => x.Blog).HasForeignKey(x => x.BlogId)

设置级联删除

  1. 1: HasMany(x => x.Posts).WithOptional(x => x.Blog).HasForeignKey(x => x.BlogId).WillCascadeOnDelete();

反转属性

在Post实体中,有两个属性:PrimaryAuthor和SecondaryAuthor,第一作者和第二作者。在Author中有两个集合属性,Code First默认不能确定哪个集合属性和Post中的导航属性相匹配。使用Fluent API配置反转属性,如下:

  1. 1: HasRequired(t => t.PrimaryAuthor).WithMany(t => t.PrimaryAuthorFor);
  1. 2: HasOptional(t => t.SecondaryAuthor).WithMany(t => t.SecondaryAuthorFor);

下面是配置一对多关系的Demo:

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

测试程序:

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

测试结果:

三、多对多

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

  1. 1: public class Post
  1. 2: {
  1. 3: public int Id { get; set; }
  1. 4: public string Title { get; set; }
  1. 5: public string Content { get; set; }
  1. 6: public DateTime PostedDate { get; set; }
  1. 7:  
  1. 8: public virtual List<Author> Authors { get; set; }
  1. 9: }
  1. 10:  
  1. 11: public class Author
  1. 12: {
  1. 13: public int Id { get; set; }
  1. 14: public string Name { get; set; }
  1. 15: public string Email { get; set; }
  1. 16: //个人简历
  1. 17: public string Bio { get; set; }
  1. 18:  
  1. 19: public virtual List<Post> Posts { get; set; }
  1. 20: }

一篇文章有多个作者,一个作者著有多篇文章。

配置多对多关系使用HasMany和WithMany方法,可以使用Map配置生成关联表的名字。

下面是配置多对多关系的Demo:

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

测试程序:

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

测试结果:

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

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

  1. 1: public class PostAuthor
  1. 2: {
  1. 3: public int PostId { get; set; }
  1. 4: public int AuthorId { get; set; }
  1. 5:  
  1. 6: public Post Post { get; set; }
  1. 7: public Author Author { get; set; }
  1. 8:  
  1. 9: public DateTime DateAdd { get; set; }
  1. 10: }

另外需要在Post和Author实体中加入一个集合属性:

  1. 1: public virtual List<PostAuthor> PostAuthors { get; set; }

另外还需要配置PostAuthor实体,具体代码如下面的Demo所示:

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

测试程序:

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

测试结果:

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

http://www.cnblogs.com/nianming/archive/2012/11/12/2767089.html

【配置关系】—Entity Framework实例详解的更多相关文章

  1. Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

  2. 转:【工欲善其事必先利其器】—Entity Framework实例详解

    开始本篇文章之前,先说一下Entity Framework 6 Alpha1在NuGet中已可用,原文链接http://blogs.msdn.com/b/adonet/archive/2012/10/ ...

  3. 【配置属性】—Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

  4. —Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

  5. 【迁移】—Entity Framework实例详解 转

    一.Entity Framework 迁移命令(get-help EntityFramework) Enable-Migrations 启用迁移 Add-Migration 为挂起的Model变化添加 ...

  6. 【迁移】—Entity Framework实例详解

    好久没有在博客园更新博客了,如今都换了新公司.前段时间写了关于EF迁移的文档,今天拿出来作为这个系列的一篇吧. 一.Entity Framework 迁移命令(get-help EntityFrame ...

  7. [转]C#综合揭秘——Entity Framework 并发处理详解

    本文转自:http://www.cnblogs.com/leslies2/archive/2012/07/30/2608784.html 引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的 ...

  8. Linq实战 之 Linq to Sql及Entity Framework操作详解

    Linq实战 之 Linq to Sql及Entity Framework操作详解 一:linq to db的框架 1. linq to sql 2. linq to ado.net entity f ...

  9. C#综合揭秘——Entity Framework 并发处理详解

    引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的错误的一种机制.从 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NET Entity Framework,.NET 都 ...

随机推荐

  1. hdu_2092_整数解

    枚举 #include <iostream> #include <cstdio> #include <cmath> using namespace std; int ...

  2. Axure:从简单搜索到联想搜索的部件制作

    导读:最近一直都在整理原型部件,要说准备的最有感触的,当属搜索框无疑.搜索框的整理,前后加起来共耗时两天多.从最开始的按钮和文本框,到后来的图示,提示和联想查询.耗费了不少的心血,有必要总结一下,留个 ...

  3. 【Luogu】P1613跑路(倍增+Floyd)

    题目链接在此 其实我看到这道题一点想法都没有 设f[i][j][k]表示用2i秒能不能从j走到k.如果可以,那j到k就可以一秒走到,它们的路径长度就是1.方程为f[i][j][k]=f[i-1][j] ...

  4. HDU——2647Reward(DFS或差分约束)

    Reward Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  5. Bzoj1083 1083: [SCOI2005]繁忙的都市【MST】

    大水题,真不知道出题者是怎么把这么水的题出的这么长的TAT 其实这题在于考语文水平,一共三个要求,前两个要求意思就是要选出的道路是树形的,最后一个要求就是要权值最小,于是整个题意说白了就是求一棵MST ...

  6. 【kmp或扩展kmp】HDU 6153 A Secret

    acm.hdu.edu.cn/showproblem.php?pid=6153 [题意] 给定字符串A和B,求B的所有后缀在A中出现次数与其长度的乘积之和 A和B的长度最大为1e6 方法一:扩展kmp ...

  7. hdu 2713

    #include<stdio.h> #include<string.h> int map[151000][2]; int max(int a,int b) {  return ...

  8. Java中的自动类型转换

    Java里所有的数值型变量可以进行类型转换,这个大家都知道,应该不需要详细解释为什么. 2 在说明自动类型转换之前必须理解这样一个原则“表数范围小的可以向表数范围大的进行自动类型转换” 3 关于jav ...

  9. 观光公交(codevs 1139)

    题目描述 Description 风景迷人的小城 Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0 分钟出现在1号 ...

  10. 【HDOJ5978】To begin or not to begin(概率)

    题意:有k个黑球和1个红球,两个轮流抽,抽到红球算赢,问先手赢的概率大还是后手大还是相等 k<=1e5 思路:手算前几项概率 大胆猜想 #include<cstdio> #inclu ...