您的位置:首页 > 其它

【配置映射】—Entity Framework实例详解

2012-11-20 00:24 232 查看
前两篇博文中的配置属性和配置关系都是配置映射,配置属性是属性的映射,配置关系式关系的映射,本篇从讲讲实体的映射。

首先,配置实体映射到表,使用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的内容,可以查看这篇文章:InheritancewithEFCodeFirst:Part3–TableperConcreteType(TPC)

四、结束语

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

如果遇到问题,可以访问EntityFramework社区,网址是www.ef-community.com。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: