有一段时间没有更新博客了,赶上今天外面下雨,而且没人约球,打算把最近对Entity Framework DBContext使用的心得梳理一下,早些时候在网上简单查过,对于最新版本的EF并没有类似的知识梳理类文章,希望对大家有所帮助。
1. 不要Code first, 也不要DB first
我为什么讨厌Code first和DB first呢?首先Code first是先写代码,数据库完全由代码生成,开发阶段尚可,一旦到了产品发布阶段,如果需要添加字段,我们总不能用 visual studio去生产环境上去更新数据库吧,听起来就很可怕。而且另外的一个问题自动是生成的数据库脚本也不可控,还不如自己提前设计好。DB first也好不了哪去,反向转过来的代码包含很多没有用的文件,而且数据库的更新还要重新走Model生成过程,简直无法理解为什么会有这样的设计。说了这么多,怎么解决呢?
数据库和领域模型分开设计,按照对应关系映射字段,使用自定义链接字串,既不使用领域模型生成数据库,也不用数据库生成领域模型,示例代码如下,SQL Code 以 Destinations和TTable表为例:
1 2 3 4 5 6 7 | CREATE TABLE [DBO].[Destinations] ( [DestinationId] [ int ] PRIMARY KEY NOT NULL , [ Name ] [nvarchar]( max ) NULL , [Country] [nvarchar]( max ) NULL , [Description] [nvarchar]( max ) NULL , [Photo] [varbinary]( max ) NULL |
1 2 3 4 5 6 7 8 9 | CREATE TABLE [TTT].[TTable] ( [Id] [ int ] PRIMARY KEY NOT NULL , [ Name ] [nvarchar]( max ) NULL ) |
Model Class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Model { public class Destination { public int DestinationId { get ; set ; } public string Name { get ; set ; } public string Country { get ; set ; } public string Description { get ; set ; } public byte [] Photo { get ; set ; } public List<lodging> Lodgings { get ; set ; } } public class Lodging { public int LodgingId { get ; set ; } public string Name { get ; set ; } public string Owner { get ; set ; } public bool IsResort { get ; set ; } public Destination Destination { get ; set ; } } public class TTable { public int Id { get ; set ; } public string Name { get ; set ; } } }</lodging> |
Connect String:
1 | < connectionstrings >< add name = "BAContext" connectionstring = "Data Source=(LocalDb)MSSQLLocalDB;Initial Catalog=DataAccess.BreakAwayContext;Integrated Security=SSPI;" providername = "System.Data.SqlClient" ></ add ></ connectionstrings > |
DB Context:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | using System.Data.Entity; using System.Data.Entity.ModelConfiguration; using Model; namespace DataAccess { public class TTableConfiguration : EntityTypeConfiguration<ttable> { public TTableConfiguration() { this .ToTable( "TTable" , "TTT" ); } } public class BreakAwayContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add( new TTableConfiguration()); } public BreakAwayContext( string connString) : base (connString) { } public DbSet<destination> Destinations { get ; set ; } public DbSet<lodging> Lodgings { get ; set ; } public DbSet<ttable> TTables { get ; set ; } } }</ttable></lodging></destination></ttable> |
2. 如果数据库的表的字段和领域模型的字段不对应,如何处理呢?比如本文的TTable表是在TTT Schema下面的, 而其他表示设计在DBO下面,最方便的方式是使用fluent API, 具体代码如请参见 TTableConfiguration Class和 OnModelCreating()方法,可配置的粒度非常细,比如可以配置领域模型和数据库的哪个Schema的哪张表的哪一列对应,本文是将TTable 类的数据库表配置为了TTT Schema下的TTable表,
1 2 3 4 5 6 7 | public class TTableConfiguration : EntityTypeConfiguration<ttable> { public TTableConfiguration() { this .ToTable( "TTable" , "TTT" ); } }</ttable> |
3. 增删该查自带事物支持,具体代码如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public static int Insert() { var destination = new Destination { Country = "Chs" , Description = "Chs is the language package" , Name = "xsss" }; using ( var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings[ "BAContext" ].ConnectionString)) { var rt = context.Destinations.Add(destination); context.SaveChanges(); return rt.DestinationId; } } public static void Update(Destination destIn) { using ( var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings[ "BAContext" ].ConnectionString)) { var dest = context.Destinations.Where(a => a.DestinationId == destIn.DestinationId).Single(); dest.Name = destIn.Name; context.SaveChanges(); } } public static void Delete( int destId) { using ( var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings[ "BAContext" ].ConnectionString)) { var destination = new Destination() { DestinationId = destId }; context.Destinations.Attach(destination); context.Destinations.Remove(destination); context.SaveChanges(); } } public static Destination Query( int destId) { using ( var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings[ "BAContext" ].ConnectionString)) { IQueryable<destination> dest = context.Destinations.Where(a => a.DestinationId == destId); return dest.Single(); } }</destination> |
4. 如果需要多个操作同时成功或者失败,需要手动开启事务,具体代码如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public static void TransactionOps() { using ( var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings[ "BAContext" ].ConnectionString)) { using ( var dbContextTransaction = context.Database.BeginTransaction()) { try { var destination = new Destination { Country = "Chs" , Description = "Chs is the language package" , Name = "xs2s" }; var destId = context.Destinations.Add(destination); context.SaveChanges(); context.Destinations.Attach(destId); context.Destinations.Remove(destId); context.SaveChanges(); dbContextTransaction.Commit(); } catch (System.Exception ex) { dbContextTransaction.Rollback(); System.Console.WriteLine(ex.ToString()); } } } } |
5. 分页查询是网站设计的常用功能,一个简单的真分页查询方法如下如下所示,
1 2 3 4 5 6 7 | public static List<destination> QueryPaging<tkey>( int pageIndex, int pageSize, Expression<func bool = "" >> whereLambda, Expression<func tkey= "" >> orderBy) { using ( var context = new BreakAwayContext(ConfigurationManager.ConnectionStrings[ "BAContext" ].ConnectionString)) { return context.Destinations.Where(whereLambda).OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); } }</func></func></tkey></destination> |
总结
本文对最新版本的Entity Framework进行增删改查操作给出了详尽的解释,并且给出了数据库和领域模型代码分开设计的完整解决方案,同时介绍了手动数据库表和领域模型映射,数据库事务实现,分页查询等常用功能,希望对大家有所帮助。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对IT俱乐部的支持。如果你想了解更多相关内容请查看下面相关链接