【配置映射】—Entity Framework实例详解
2012-11-20 00:24
232 查看
前两篇博文中的配置属性和配置关系都是配置映射,配置属性是属性的映射,配置关系式关系的映射,本篇从讲讲实体的映射。
首先,配置实体映射到表,使用ToTable方法,它接受两个参数,第一个参数是表的名称,第二个参数是Schema名称。
[code]{
[/code]
映射实体到一个表中,实体需要遵循以下规则:
1.实体之间必须是一对一的关系。
2.实体必须共用主键。
使用FluentAPI配置Blog和BlogLogo映射到一个表,使用ToTable方法,如下:
[code]modelBuilder.Entity<BlogLogo>().ToTable("Blogs");
[/code]
完整的Demo如下:
测试程序:
测试结果:
下面是使用到的类:
[code]{
[/code]
使用FluentAPI将Blog个映射到多个表,使用Map方法,如下:
[code]{
[/code]
完整的Demo如下:
测试程序:
测试结果:
TPT,TablePerType,就是基类存放到一张主表,每个派生类存放到一张表,通过外键与主表关联。
TPC,TablePerConcreteType,就是基类和派生类都存放到单独的表中,没有主表。
下面是继承部分使用到的类:
[code]{
[/code]
首先来看一下TPH
配置继承为TPH,使用到一些新的配置方法:Requires和HasValue。CodeFirst默认辨别列的名称为Discriminator,辨别列的值为类的名称。Requires配置辨别列的名称,HasValue定义辨别列的值。
下面看TPH的Demo:
测试程序:
测试结果:
TPT
配置继承为TPT,只需使用ToTable显示将派生类映射到表即可。
TPT的Demo,只需修改PictureBlog和VideoBlog的配置,其他全部一样:
最后生成的数据库表如下图所示:
Blogs表,只包含基类中的属性:
PictureBlogs表,只包含派生类中的属性:
VideoBlogs表:
TPC
TPC和TPT差不多,TPC使用MapInheritedProperties配置。MapInheritedProperties告诉CodeFirst要映射基类中的属性到派生类的表中。
代码如下所示:
现在再运行程序,会出现下面的错误:
出现这个问题的主要问题是因为不支持多态关联。归根到底,就是在数据库中关联表示为外键关系,在TPC中,子类都映射到不同的表中,所以有多个关联指向基类不能使用简单的外键关系表示。
解决办法:
配置Blog的主键产生之的方式为None,在创建对象时,手动给主键赋值。
[code]{
[/code]
运行结果:
PictureBlogs表:
VideoBlogs表:
关于TPC的内容,可以查看这篇文章:InheritancewithEFCodeFirst:Part3–TableperConcreteType(TPC)
点击查看《EntityFramework实例详解》系列的其他文章。
如果遇到问题,可以访问EntityFramework社区,网址是www.ef-community.com。
首先,配置实体映射到表,使用ToTable方法,它接受两个参数,第一个参数是表的名称,第二个参数是Schema名称。
ToTable("Destination","baga");
一、配置多个实体到一个表
下面是用到的类:publicclassBlog
[code]{
publicintId{get;set;}
publicDateTimeCreationdate{get;set;}
publicstringShortDescription{get;set;}
publicstringTitle{get;set;}
publicvirtualBlogLogoBlogLogo{get;set;}
}
publicclassBlogLogo
{
publicintId{get;set;}
publicbyte[]Logo{get;set;}
}
[/code]
映射实体到一个表中,实体需要遵循以下规则:
1.实体之间必须是一对一的关系。
2.实体必须共用主键。
使用FluentAPI配置Blog和BlogLogo映射到一个表,使用ToTable方法,如下:
modelBuilder.Entity<Blog>().ToTable("Blogs");
[code]modelBuilder.Entity<BlogLogo>().ToTable("Blogs");
[/code]
完整的Demo如下:
publicclassBlog
{
publicintId{get;set;}
publicDateTimeCreationdate{get;set;}
publicstringShortDescription{get;set;}
publicstringTitle{get;set;}
publicvirtualBlogLogoBlogLogo{get;set;}
}
publicclassBlogLogo
{
publicintId{get;set;}
publicbyte[]Logo{get;set;}
}
publicclassBlogConfiguration:EntityTypeConfiguration<Blog>
{
publicBlogConfiguration()
{
ToTable("Blogs");
HasKey(x=>x.Id);
Property(x=>x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
Property(x=>x.Title).HasMaxLength(175);
HasRequired(x=>x.BlogLogo).WithRequiredPrincipal();
}
}
publicclassBlogLogoConfiguration:EntityTypeConfiguration<BlogLogo>
{
publicBlogLogoConfiguration()
{
ToTable("Blogs");
HasKey(x=>x.Id);
Property(x=>x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
}
}
publicclassBlogContext:DbContext
{
publicDbSet<Blog>Blogs{get;set;}
protectedoverridevoidOnModelCreating(DbModelBuildermodelBuilder)
{
modelBuilder.Configurations.Add(newBlogConfiguration());
modelBuilder.Configurations.Add(newBlogLogoConfiguration());
base.OnModelCreating(modelBuilder);
}
publicIQueryable<T>Find<T>()whereT:class
{
returnthis.Set<T>();
}
publicvoidRefresh()
{
this.ChangeTracker.Entries().ToList().ForEach(x=>x.Reload());
}
publicvoidCommit()
{
this.SaveChanges();
}
}
publicclassInitializer:DropCreateDatabaseAlways<BlogContext>
{
publicInitializer()
{
}
protectedoverridevoidSeed(BlogContextcontext)
{
context.Set<Blog>().Add(newBlog()
{
Creationdate=DateTime.Now,
ShortDescription="Testing",
Title="TestBlog",
BlogLogo=newBlogLogo(){Logo=newbyte[0]}
});
context.SaveChanges();
}
}
测试程序:
[TestMethod]
publicvoidShouldReturnABlogWithLogo()
{
//Arrange
varinit=newInitializer();
varcontext=newBlogContext();
init.InitializeDatabase(context);
//Act
varpost=context.Blogs.FirstOrDefault();
//Assert
Assert.IsNotNull(post);
Assert.IsNotNull(post.BlogLogo);
}
测试结果:
二、配置一个实体到多个表
拿用户和用户信息来说,在映射到已有的数据库时,有可能用户包含的信息比较多,为了性能或其他一些原因,不经常用的用户信息存放到单独的表中,经常使用的信息则存放到User表中,但是使用类表示时,希望将用户所有的信息放到一个类中,在映射时,就需要将实体分割。下面是使用到的类:
publicclassBlog
[code]{
publicintId{get;set;}
publicDateTimeCreationdate{get;set;}
publicstringShortDescription{get;set;}
publicstringTitle{get;set;}
publicstringDescription{get;set;}
publicstringAboutTheAuthor{get;set;}
}
[/code]
使用FluentAPI将Blog个映射到多个表,使用Map方法,如下:
Map(m=>
[code]{
m.Properties(t=>new{t.Id,t.Title,t.ShortDescription});
m.ToTable("Blog");
})
.Map(m=>
{
m.Properties(t=>new{t.Description,t.Creationdate,t.AboutTheAuthor});
m.ToTable("BlogDetails");
});
[/code]
完整的Demo如下:
publicclassBlog
{
publicintId{get;set;}
publicDateTimeCreationdate{get;set;}
publicstringShortDescription{get;set;}
publicstringTitle{get;set;}
publicstringDescription{get;set;}
publicstringAboutTheAuthor{get;set;}
}
publicclassBlogConfiguration:EntityTypeConfiguration<Blog>
{
publicBlogConfiguration()
{
Map(m=>
{
m.Properties(t=>new{t.Id,t.Title,t.ShortDescription});
m.ToTable("Blog");
})
.Map(m=>
{
m.Properties(t=>new{t.Description,t.Creationdate,t.AboutTheAuthor});
m.ToTable("BlogDetails");
});
HasKey(x=>x.Id);
Property(x=>x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
}
}
publicclassBlogContext:DbContext,IUnitOfWork
{
protectedoverridevoidOnModelCreating(DbModelBuildermodelBuilder)
{
modelBuilder.Configurations.Add(newBlogConfiguration());
base.OnModelCreating(modelBuilder);
}
publicDbSet<Blog>Blogs{get;set;}
publicIQueryable<T>Find<T>()whereT:class
{
returnthis.Set<T>();
}
publicvoidRefresh()
{
this.ChangeTracker.Entries().ToList().ForEach(x=>x.Reload());
}
publicvoidCommit()
{
this.SaveChanges();
}
}
publicinterfaceIUnitOfWork
{
IQueryable<T>Find<T>()whereT:class;
voidRefresh();
voidCommit();
}
publicclassInitializer:DropCreateDatabaseAlways<BlogContext>
{
publicInitializer()
{
}
protectedoverridevoidSeed(BlogContextcontext)
{
context.Set<Blog>().Add(newBlog()
{
Creationdate=DateTime.Now,
ShortDescription="Testing",
Title="TestBlog",
Description="LongTest",
AboutTheAuthor="Mememe"
});
context.SaveChanges();
}
}
测试程序:
[TestMethod]
publicvoidShouldReturnABlogWithAuthorDetails()
{
//Arrange
varinit=newInitializer();
varcontext=newBlogContext();
init.InitializeDatabase(context);
//Act
varpost=context.Blogs.FirstOrDefault();
//Assert
Assert.IsNotNull(post);
Assert.IsNotNull(post.AboutTheAuthor);
}
测试结果:
三、继承
TPH,TablePerHierarchy,就是基类和派生类都映射到一张表,使用辨别列区分。TPT,TablePerType,就是基类存放到一张主表,每个派生类存放到一张表,通过外键与主表关联。
TPC,TablePerConcreteType,就是基类和派生类都存放到单独的表中,没有主表。
下面是继承部分使用到的类:
publicclassBlog
[code]{
publicintId{get;set;}
publicDateTimeCreationdate{get;set;}
publicstringShortDescription{get;set;}
publicstringTitle{get;set;}
publicstringAboutTheAuthor{get;set;}
}
publicclassPictureBlog:Blog
{
//想不起来用什么字段好了,弄个“图片介绍”吧
publicstringPicDescription{get;set;}
}
publicclassVideoBlog:Blog
{
//视频介绍
publicstringVideoDescription{get;set;}
}
[/code]
首先来看一下TPH
配置继承为TPH,使用到一些新的配置方法:Requires和HasValue。CodeFirst默认辨别列的名称为Discriminator,辨别列的值为类的名称。Requires配置辨别列的名称,HasValue定义辨别列的值。
下面看TPH的Demo:
[TestMethod]
publicvoidShouldReturnABlogWithTypeSafety()
{
//Arrange
varinit=newInitializer();
varcontext=new
BlogContext(Settings.Default.BlogConnection);
init.InitializeDatabase(context);
//Act
varpictureBlog=
context.Set<PictureBlog>().FirstOrDefault();
varvideoBlog=context.Set<VideoBlog>().FirstOrDefault();
//Assert
Assert.IsNotNull(pictureBlog);
Assert.IsNotNull(videoBlog);
}
}
测试程序:
[TestMethod]
publicvoidShouldReturnABlogWithTypeSafety()
{
//Arrange
varinit=newInitializer();
varcontext=newBlogContext();
init.InitializeDatabase(context);
//Act
varpictureBlog=context.Set<PictureBlog>().FirstOrDefault();
varvideoBlog=context.Set<VideoBlog>().FirstOrDefault();
//Assert
Assert.IsNotNull(pictureBlog);
Assert.IsNotNull(videoBlog);
}
测试结果:
TPT
配置继承为TPT,只需使用ToTable显示将派生类映射到表即可。
TPT的Demo,只需修改PictureBlog和VideoBlog的配置,其他全部一样:
publicclassPictureBlogConfiguration:EntityTypeConfiguration<PictureBlog>
{
publicPictureBlogConfiguration()
{
Map(m=>
{
m.ToTable("PictureBlogs");
});
}
}
publicclassVideoBlogConfiguration:EntityTypeConfiguration<VideoBlog>
{
publicVideoBlogConfiguration()
{
Map(m=>
{
m.ToTable("VideoBlogs");
});
}
}
最后生成的数据库表如下图所示:
Blogs表,只包含基类中的属性:
PictureBlogs表,只包含派生类中的属性:
VideoBlogs表:
TPC
TPC和TPT差不多,TPC使用MapInheritedProperties配置。MapInheritedProperties告诉CodeFirst要映射基类中的属性到派生类的表中。
代码如下所示:
publicclassBlogConfiguration:EntityTypeConfiguration<Blog>
{
publicBlogConfiguration()
{
ToTable("Blogs");
HasKey(t=>t.Id);
Property(t=>t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("BlogId");
Property(t=>t.Title).HasMaxLength(175);
}
}
publicclassPictureBlogConfiguration:EntityTypeConfiguration<PictureBlog>
{
publicPictureBlogConfiguration()
{
Map(m=>
{
m.ToTable("PictureBlogs");
m.MapInheritedProperties();
});
}
}
现在再运行程序,会出现下面的错误:
出现这个问题的主要问题是因为不支持多态关联。归根到底,就是在数据库中关联表示为外键关系,在TPC中,子类都映射到不同的表中,所以有多个关联指向基类不能使用简单的外键关系表示。
解决办法:
配置Blog的主键产生之的方式为None,在创建对象时,手动给主键赋值。
publicclassBlogConfiguration:EntityTypeConfiguration<Blog>
[code]{
publicBlogConfiguration()
{
ToTable("Blogs");
HasKey(t=>t.Id);
//配置不自动生成值
Property(t=>t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None).HasColumnName("BlogId");
Property(t=>t.Title).HasMaxLength(175);
}
}
[/code]
protectedoverridevoidSeed(BlogContextcontext)
{
context.Set<PictureBlog>().Add(newPictureBlog()
{
//手动给主键赋值
Id=1,
Creationdate=DateTime.Now,
ShortDescription="Testing",
Title="TestBlog",
AboutTheAuthor="Mememe",
PicDescription="Thisisapicturedescription"
});
context.Set<VideoBlog>().Add(newVideoBlog()
{
Id=2,
Creationdate=DateTime.Now,
ShortDescription="Testing",
Title="TestBlog",
AboutTheAuthor="Mememe",
VideoDescription="Thisisavideodescription"
});
context.SaveChanges();
}
}
运行结果:
PictureBlogs表:
VideoBlogs表:
关于TPC的内容,可以查看这篇文章:
四、结束语
如果遇到问题,可以访问
相关文章推荐
- SSH——Hibernate继承关系映射详解(配置+实例+总结)
- 【配置属性】—Entity Framework实例详解
- log4j.properties配置详解与实例-全部测试通过
- [置顶] linux中用eclipse开发Hadoop mapreduce与Hive UDF实例详解及其配置说明
- vue音乐播放器插件vue-aplayer的配置及其使用实例详解
- Spring集成Mybatis配置映射文件方法详解
- log4j.properties配置详解与实例
- Nginx负载均衡配置实例详解
- Nginx负载均衡配置实例详解
- Nginx负载均衡配置实例详解
- Struts2拦截器Interceptor的原理与配置实例详解
- Spring Cloud 覆写远端的配置属性实例详解
- log4j.properties配置详解与实例-全部测试通过
- Struts2配置详解_配置Action之通配符映射
- linux系统中的DNS服务器介绍及配置实例详解(二)
- log4j.properties配置详解与实例
- Nginx负载均衡配置实例详解
- Nginx负载均衡配置实例详解
- Mybatis的配置文件和映射文件详解
- NHibernate配置文件和映射文件的详解