博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【配置映射】—Entity Framework实例详解
阅读量:6568 次
发布时间:2019-06-24

本文共 12117 字,大约阅读时间需要 40 分钟。

前两篇博文中的配置属性和配置关系都是配置映射,配置属性是属性的映射,配置关系式关系的映射,本篇从讲讲实体的映射。

首先,配置实体映射到表,使用ToTable方法,它接受两个参数,第一个参数是表的名称,第二个参数是Schema名称。

1:              ToTable("Destination", "baga");

一、配置多个实体到一个表

下面是用到的类:

1:      public class Blog
2:      {
3:          public int Id { get; set; }
4:          public DateTime Creationdate { get; set; }
5:          public string ShortDescription { get; set; }
6:          public string Title { get; set; }
7:          public virtual BlogLogo BlogLogo { get; set; }
8:      }
9:   
10:      public class BlogLogo
11:      {
12:          public int Id { get; set; }
13:          public byte[] Logo { get; set; }
14:      }

映射实体到一个表中,实体需要遵循以下规则:

1. 实体之间必须是一对一的关系。

2. 实体必须共用主键。

使用Fluent API 配置Blog和BlogLogo映射到一个表,使用ToTable方法,如下:

1:              modelBuilder.Entity
().ToTable("Blogs");
2:              modelBuilder.Entity
().ToTable("Blogs");

完整的Demo如下:

1: public class Blog
2: {
3:     public int Id { get; set; }
4:     public DateTime Creationdate { get; set; }
5:     public string ShortDescription { get; set; }
6:     public string Title { get; set; }
7:     public virtual BlogLogo BlogLogo { get; set; }
8: }
9: 
10: public class BlogLogo
11: {
12:     public int Id { get; set; }
13:     public byte[] Logo { get; set; }
14: }
15: 
16: public class BlogConfiguration : EntityTypeConfiguration
17: {
18:     public BlogConfiguration()
19:     {
20:         ToTable("Blogs");
21:         HasKey(x => x.Id);
22:         Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
23:         Property(x => x.Title).HasMaxLength(175);
24:         HasRequired(x => x.BlogLogo).WithRequiredPrincipal();
25:     }
26: }
27: 
28: public class BlogLogoConfiguration : EntityTypeConfiguration
29: {
30:     public BlogLogoConfiguration()
31:     {
32:         ToTable("Blogs");
33:         HasKey(x => x.Id);
34:         Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
35:     }
36: }
37: 
38: 
39: public class BlogContext : DbContext
40: {
41:     public DbSet
Blogs { get; set; }
42: 
43:     protected override void OnModelCreating(DbModelBuilder modelBuilder)
44:     {
45:         modelBuilder.Configurations.Add(new BlogConfiguration());
46:         modelBuilder.Configurations.Add(new BlogLogoConfiguration());
47:         base.OnModelCreating(modelBuilder);
48:     }
49: 
50:     public IQueryable
Find
() where T : class
51:     {
52:         return this.Set
();
53:     }
54: 
55:     public void Refresh()
56:     {
57:         this.ChangeTracker.Entries().ToList().ForEach(x => x.Reload());
58:     }
59:     public void Commit()
60:     {
61:         this.SaveChanges();
62:     }
63: }
64: 
65: public class Initializer : DropCreateDatabaseAlways
66: {
67:     public Initializer()
68:     {
69:     }
70: 
71:     protected override void Seed(BlogContext context)
72:     {
73:         context.Set
().Add(new Blog()
74:         {
75:             Creationdate = DateTime.Now,
76:             ShortDescription = "Testing",
77:             Title = "Test Blog",
78:             BlogLogo = new BlogLogo() { Logo = new byte[0] }
79:         });
80:         context.SaveChanges();
81:     }
82: }

测试程序:

1: [TestMethod]
2: public void ShouldReturnABlogWithLogo()
3: {
4:     //Arrange
5:     var init = new Initializer();
6:     var context = new BlogContext();
7:     init.InitializeDatabase(context);
8:     //Act
9:     var post = context.Blogs.FirstOrDefault();
10:     //Assert
11:     Assert.IsNotNull(post);
12:     Assert.IsNotNull(post.BlogLogo);
13: }

测试结果:

二、配置一个实体到多个表

拿用户和用户信息来说,在映射到已有的数据库时,有可能用户包含的信息比较多,为了性能或其他一些原因,不经常用的用户信息存放到单独的表中,经常使用的信息则存放到User表中,但是使用类表示时,希望将用户所有的信息放到一个类中,在映射时,就需要将实体分割。

下面是使用到的类:

1:      public class Blog
2:      {
3:          public int Id { get; set; }
4:          public DateTime Creationdate { get; set; }
5:          public string ShortDescription { get; set; }
6:          public string Title { get; set; }
7:          public string Description { get; set; }
8:          public string AboutTheAuthor { get; set; }
9:      }

使用Fluent API 将Blog个映射到多个表,使用Map方法,如下:

1:              Map(m =>
2:              {
3:                  m.Properties(t => new { t.Id, t.Title, t.ShortDescription });
4:                  m.ToTable("Blog");
5:              })
6:              .Map(m =>
7:              {
8:                  m.Properties(t => new { t.Description, t.Creationdate, t.AboutTheAuthor });
9:                  m.ToTable("BlogDetails");
10:              });

完整的Demo如下:

1: public class Blog
2: {
3:     public int Id { get; set; }
4:     public DateTime Creationdate { get; set; }
5:     public string ShortDescription { get; set; }
6:     public string Title { get; set; }
7:     public string Description { get; set; }
8:     public string AboutTheAuthor { get; set; }
9: }
10: 
11: public class BlogConfiguration : EntityTypeConfiguration
12: {
13:     public BlogConfiguration()
14:     {
15:         Map(m =>
16:         {
17:             m.Properties(t => new { t.Id, t.Title, t.ShortDescription });
18:             m.ToTable("Blog");
19:         })
20:         .Map(m =>
21:         {
22:             m.Properties(t => new { t.Description, t.Creationdate, t.AboutTheAuthor });
23:             m.ToTable("BlogDetails");
24:         });
25:         HasKey(x => x.Id);
26:         Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
27:     }
28: }
29: 
30: public class BlogContext : DbContext, IUnitOfWork
31: {
32:     protected override void OnModelCreating(DbModelBuilder modelBuilder)
33:     {
34:         modelBuilder.Configurations.Add(new BlogConfiguration());
35:         base.OnModelCreating(modelBuilder);
36:     }
37:     public DbSet
Blogs { get; set; }
38: 
39:     public IQueryable
Find
() where T : class
40:     {
41:         return this.Set
();
42:     }
43: 
44:     public void Refresh()
45:     {
46:         this.ChangeTracker.Entries().ToList().ForEach(x => x.Reload());
47:     }
48: 
49:     public void Commit()
50:     {
51:         this.SaveChanges();
52:     }
53: }
54: 
55: public interface IUnitOfWork
56: {
57:     IQueryable
Find
() where T : class;
58:     void Refresh();
59:     void Commit();
60: }
61: 
62: public class Initializer : DropCreateDatabaseAlways
63: {
64:     public Initializer()
65:     {
66:     }
67:     protected override void Seed(BlogContext context)
68:     {
69:         context.Set
().Add(new Blog()
70:         {
71:             Creationdate = DateTime.Now,
72:             ShortDescription = "Testing",
73:             Title = "Test Blog",
74:             Description = "Long Test",
75:             AboutTheAuthor = "Me me me"
76:         });
77:         context.SaveChanges();
78:     }
79: }

测试程序:

1: [TestMethod]
2: public void ShouldReturnABlogWithAuthorDetails()
3: {
4:     //Arrange
5:     var init = new Initializer();
6:     var context = new BlogContext();
7:     init.InitializeDatabase(context);
8:     //Act
9:     var post = context.Blogs.FirstOrDefault();
10:     //Assert
11:     Assert.IsNotNull(post);
12:     Assert.IsNotNull(post.AboutTheAuthor);
13: }

测试结果:

三、继承

TPH,Table Per Hierarchy,就是基类和派生类都映射到一张表,使用辨别列区分。

TPT,Table Per Type,就是基类存放到一张主表,每个派生类存放到一张表,通过外键与主表关联。

TPC,Table Per Concrete Type,就是基类和派生类都存放到单独的表中,没有主表。

下面是继承部分使用到的类:

1:      public class Blog
2:      {
3:          public int Id { get; set; }
4:          public DateTime Creationdate { get; set; }
5:          public string ShortDescription { get; set; }
6:          public string Title { get; set; }
7:          public string AboutTheAuthor { get; set; }
8:      }
9:   
10:      public class PictureBlog : Blog
11:      {
12:          //想不起来用什么字段好了,弄个“图片介绍”吧
13:          public string PicDescription { get; set; }
14:      }
15:   
16:      public class VideoBlog : Blog
17:      {
18:          //视频介绍
19:          public string VideoDescription { get; set; }
20:      }

首先来看一下TPH

配置继承为TPH,使用到一些新的配置方法:Requires和HasValue。Code First默认辨别列的名称为Discriminator,辨别列的值为类的名称。Requires配置辨别列的名称,HasValue定义辨别列的值。

下面看TPH的Demo:

1: [TestMethod]
2: public void ShouldReturnABlogWithTypeSafety()
3: {
4: //Arrange
5: var init = new Initializer();
6: var context = new
7: BlogContext(Settings.Default.BlogConnection);
8: init.InitializeDatabase(context);
9: //Act
10: var pictureBlog =
11: context.Set
().FirstOrDefault();
12: var videoBlog = context.Set
().FirstOrDefault();
13: //Assert
14: Assert.IsNotNull(pictureBlog);
15: Assert.IsNotNull(videoBlog);
16: }
17: }

测试程序:

1: [TestMethod]
2: public void ShouldReturnABlogWithTypeSafety()
3: {
4:     //Arrange
5:     var init = new Initializer();
6:     var context = new BlogContext();
7:     init.InitializeDatabase(context);
8:     //Act
9:     var pictureBlog =context.Set
().FirstOrDefault();
10:     var videoBlog = context.Set
().FirstOrDefault();
11:     //Assert
12:     Assert.IsNotNull(pictureBlog);
13:     Assert.IsNotNull(videoBlog);
14: }

测试结果:

TPT

配置继承为TPT,只需使用ToTable显示将派生类映射到表即可。

TPT的Demo,只需修改PictureBlog和VideoBlog的配置,其他全部一样:

1: public class PictureBlogConfiguration : EntityTypeConfiguration
2: {
3:     public PictureBlogConfiguration()
4:     {
5:         Map(m =>
6:         {
7:             m.ToTable("PictureBlogs");
8:         });
9:     }
10: }
11: 
12: public class VideoBlogConfiguration : EntityTypeConfiguration
13: {
14:     public VideoBlogConfiguration()
15:     {
16:         Map(m =>
17:         {
18:             m.ToTable("VideoBlogs");
19:         });
20:     }
21: }

最后生成的数据库表如下图所示:

Blogs表,只包含基类中的属性:

PictureBlogs表,只包含派生类中的属性:

VideoBlogs表:

TPC

TPC和TPT差不多,TPC使用MapInheritedProperties配置。MapInheritedProperties告诉Code First要映射基类中的属性到派生类的表中。

代码如下所示:

1: public class BlogConfiguration : EntityTypeConfiguration
2: {
3:     public BlogConfiguration()
4:     {
5:         ToTable("Blogs");
6:         HasKey(t => t.Id);
7:         Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
8:         Property(t => t.Title).HasMaxLength(175);
9:     }
10: }
11: 
12: public class PictureBlogConfiguration : EntityTypeConfiguration
13: {
14:     public PictureBlogConfiguration()
15:     {
16:         Map(m =>
17:         {
18:             m.ToTable("PictureBlogs");
19:             m.MapInheritedProperties();
20:         });
21:     }
22: }

现在再运行程序,会出现下面的错误:

出现这个问题的主要问题是因为不支持多态关联。归根到底,就是在数据库中关联表示为外键关系,在TPC中,子类都映射到不同的表中,所以有多个关联指向基类不能使用简单的外键关系表示。

解决办法:

配置Blog的主键产生之的方式为None,在创建对象时,手动给主键赋值。

1:  public class BlogConfiguration : EntityTypeConfiguration
2:  {
3:      public BlogConfiguration()
4:      {
5:          ToTable("Blogs");
6:          HasKey(t => t.Id);
7:          //配置不自动生成值
8:          Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None).HasColumnName("BlogId");
9:          Property(t => t.Title).HasMaxLength(175);
10:      }
11:  }
1: protected override void Seed(BlogContext context)
2: {
3:     context.Set
().Add(new PictureBlog()
4:     {
5:         //手动给主键赋值
6:         Id = 1,
7:         Creationdate = DateTime.Now,
8:         ShortDescription = "Testing",
9:         Title = "Test Blog",
10:         AboutTheAuthor = "Me me me",
11:         PicDescription = "This is a picture description"
12:     });
13:     context.Set
().Add(new VideoBlog()
14:     {
15:         Id = 2,
16:         Creationdate = DateTime.Now,
17:         ShortDescription = "Testing",
18:         Title = "Test Blog",
19:         AboutTheAuthor = "Me me me",
20:         VideoDescription = "This is a video description"
21:     });
22:     context.SaveChanges();
23: }
24:     }

运行结果:

PictureBlogs表:

VideoBlogs表:

关于TPC的内容,可以查看这篇文章:

四、结束语

系列的其他文章。

如果遇到问题,可以访问,网址是

转载地址:http://sqpjo.baihongyu.com/

你可能感兴趣的文章
剖析 Laravel 计划任务--事件属性
查看>>
Micronaut教程:如何使用基于JVM的框架构建微服务
查看>>
检查IP是否可用的方法
查看>>
互联网架构师必备技术 Docker仓库与Java应用服务动态发布那些事
查看>>
Intellij IDEA 2018.2 搭建Spring Boot 应用
查看>>
作为数据科学家,我都有哪些弱点
查看>>
(转)线程安全的CopyOnWriteArrayList介绍
查看>>
对LinqtoExcel的扩展 【数据有限性,逻辑有效性】
查看>>
WPF TreeView HierarchicalDataTemplate
查看>>
32岁老程序员的现状和尴尬,无奈中透露些许悲凉,有选择却更痛苦
查看>>
WPF MeshGeometry3D
查看>>
puppet cron 模块
查看>>
mysql 协议的ResultsetRow包及解析
查看>>
Ymal格式转Properties格式
查看>>
一个生成全局唯一Sequence ID的高并发工厂类 (Java)
查看>>
调优之系统篇--cpu,内存
查看>>
解决jQuery和其它库的冲突
查看>>
写在除夕夜
查看>>
JAVA中的list去重复
查看>>
JAVA 代码里中文乱码问题
查看>>