Repository模式--采用EF Fluent API使用EntityTypeConfiguration分文件配置Model映射关系

Repository模式--采用EF Fluent API使用EntityTypeConfiguration分文件配置Model映射关系

Posted By : 蓝狐

Updated On : 2015-07-19

EF中类EntityTypeConfiguration是一个很有用的类,在nopCommerence中就使用这个类来分文件分文件配置Model映射关系。今天我就来谈谈Repository模式在Entity Framework Code First中使用EntityTypeConfiguration的实现例子。

背景

为了简化我们就只使用两个表:分类表Category,产品类Product。最终项目结构如下:

Repository模式--采用EF Fluent API使用EntityTypeConfiguration分文件配置Model映射关系_第1张图片

注意:EfRepPatTest.Entity和EfRepPatTest.Data是类库项目,EfRepPatTest.Implementation是控制台项目。项目EfRepPatTest.Data需要对Entity Framework类库的引用。

BaseEntity.cs

创建一个所有实体的基类BaseEntity,把一些公共的属性封装在里面。

 
  1. public class BaseEntity
  2. {
  3. public T Id { get; set; }
  4. }

这样表示所有实体都有一个字段为Id,类型为泛型这样可以满足所有类型的情况。

IRepository.cs:

下面定义一个泛型的接口IRepository,其中包括一个泛型的增、删、改。

 
  1. public interface IRepository where TEntity:class
  2. {
  3. IQueryable GetAll();
  4. TEntity GetById(object id);
  5. void Insert(TEntity entity);
  6. void Update(TEntity entity);
  7. void Delete(TEntity entity);
  8. }

Category.cs:

实体分类类

 
  1. public class Category:BaseEntity
  2. {
  3. public virtual string Name { get; set; }
  4.  
  5. public List Products { get; set; }
  6. }

Product.cs:

实体产品类

 
  1. public class Product:BaseEntity
  2. {
  3. public virtual int CategoryId { get; set; }
  4. public virtual Category Category { get; set; }
  5. public virtual string Name { get; set; }
  6. public virtual int MinimumStockLevel { get; set; }
  7. }

IDbContext.cs:

接口IDbContext封装一些EF的公共接口方法。

 
  1. public interface IDbContext
  2. {
  3.  
  4. IDbSet Set() where TEntity:class;
  5. int SaveChanges();
  6. void Dispose();
  7. }

DataContext.cs:

 
  1. public class DataContext: DbContext,IDbContext
  2. {
  3. public new IDbSet Set() where TEntity : class
  4. {
  5. return base.Set();
  6. }
  7. }

CategoryMap.cs:

分类映射类继承于EntityTypeConfigureation

 
  1. public class CategoryMap:EntityTypeConfiguration
  2. {
  3. public CategoryMap()
  4. {
  5. ToTable("Category");
  6. HasKey(c => c.Id).Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
  7. Property(c => c.Name).IsRequired().HasMaxLength(50);
  8. }
  9. }

ProductMap.cs:

产品类映射类继承于EntityTypeConfigureation

 
  1. public class ProductMap:EntityTypeConfiguration
  2. {
  3. public ProductMap()
  4. {
  5. ToTable("Product");
  6. HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
  7. //CategoryId as foreign key
  8. HasRequired(p => p.Category)
  9. .WithMany(c=>c.Products)
  10. .HasForeignKey(p => p.CategoryId);
  11. Property(p => p.Name).IsRequired().HasMaxLength(100);
  12. Property(p => p.MinimumStockLevel);
  13. }
  14. }

在类DataContext中重写OnModelCreating方法依次加上我们新建的EF的Map配置文件,加入以下代码:

 
  1. modelBuilder.Configurations.Add(new CategoryMap());
  2. modelBuilder.Configurations.Add(new ProductMap());
  3. base.OnModelCreating(modelBuilder);

上面的代码可以优化一下,可以利用反射自动添加EF的Map配置文件,如下:

 
  1. public class DataContext: DbContext,IDbContext
  2. {
  3. public new IDbSet Set() where TEntity : class
  4. {
  5. return base.Set();
  6. }
  7.  
  8. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  9. {
  10. var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
  11. .Where(type => !String.IsNullOrEmpty(type.Namespace))
  12. .Where(type => type.BaseType != null && type.BaseType.IsGenericType &&
  13. type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
  14. foreach (var type in typesToRegister)
  15. {
  16. dynamic configurationInstance = Activator.CreateInstance(type);
  17. modelBuilder.Configurations.Add(configurationInstance);
  18. }
  19.  
  20. base.OnModelCreating(modelBuilder);
  21. }
  22.  
  23. }

这样的好处是以后新加EF的实体Map类,不用修改DataContext。

RepositoryService.cs:

IRepositroy接口的一个具体实现的RepositoryService,数据访问采用EF的IDbContext。

 
  1. public class RepositoryService:IRepository where TEntity:class
  2. {
  3. private IDbContext Context;
  4.  
  5. private IDbSet Entities
  6. {
  7. get { return this.Context.Set(); }
  8. }
  9.  
  10. public RepositoryService(IDbContext context)
  11. {
  12. this.Context = context;
  13.  
  14. }
  15.  
  16. public IQueryable GetAll()
  17. {
  18. return Entities.AsQueryable();
  19. }
  20.  
  21. public TEntity GetById(object id)
  22. {
  23. return Entities.Find(id);
  24. }
  25.  
  26. public void Insert(TEntity entity)
  27. {
  28. Entities.Add(entity);
  29. }
  30.  
  31. public void Update(TEntity entity)
  32. {
  33. if (entity == null)
  34. throw new ArgumentNullException("entity");
  35.  
  36. this.Context.SaveChanges();
  37. }
  38.  
  39. public void Delete(TEntity entity)
  40. {
  41. Entities.Remove(entity);
  42. }
  43.  
  44. public void Dispose()
  45. {
  46. Dispose(true);
  47. GC.SuppressFinalize(this);
  48. }
  49. protected virtual void Dispose(bool disposing)
  50. {
  51. if (disposing)
  52. {
  53. if (this.Context != null)
  54. {
  55. this.Context.Dispose();
  56. this.Context = null;
  57. }
  58. }
  59. }
  60. }

新建一个类DataBaseInitializer为EF Code First数据库访问的初始化类。

 
  1. public class DataBaseInitializer : IDatabaseInitializer
  2. {
  3. public void InitializeDatabase(DataContext context)
  4. {
  5. context.Database.CreateIfNotExists();
  6. }
  7. }

新建一个控制台程序来测试上面的代码Program.cs:

 
  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. var context = new DataContext();
  6. var dataBaseInitializer = new DataBaseInitializer();
  7. dataBaseInitializer.InitializeDatabase(context);
  8.  
  9. var categoryRepository = new RepositoryService(context);
  10.  
  11. //Adding category in the category entity
  12. var category = new Category()
  13. {
  14. Name = "Baverage"
  15. };
  16. var products = new List();
  17.  
  18. //Adding product in the product entity
  19. var product = new Product()
  20. {
  21. Name = "Soft Drink A",
  22. MinimumStockLevel = 50
  23. };
  24. products.Add(product);
  25.  
  26. product = new Product()
  27. {
  28. Name = "Soft Drink B",
  29. MinimumStockLevel = 30
  30. };
  31. products.Add(product);
  32.  
  33. category.Products = products;
  34.  
  35. //Insert category and save changes
  36. categoryRepository.Insert(category);
  37. context.SaveChanges();
  38.  
  39. ///
  40. /For the next project we shall add Dependency Injection
  41. But now we have add a Service layer for test manually//
  42. ///
  43. IProductService productRepository = new ProductService();
  44.  
  45. Console.WriteLine("\n");
  46. Console.WriteLine("Product List:");
  47. Console.WriteLine("-------------------------------------------------");
  48. foreach (var product1 in productRepository.GetAll())
  49. {
  50. Console.WriteLine(string.Format("Product Name : {0}",product1.Name));
  51. if (product1.Id == 9)
  52. {
  53.  
  54. product1.Name = "Soft Drink AAA";
  55. productRepository.Update(product1);
  56. }
  57. }
  58. Console.WriteLine("Press any key to exit");
  59. Console.ReadKey();
  60. }
  61. }

在配置文件添加数据库的链接。

App.config:

 
  1. type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection,
  2. EntityFramework, Version=4.4.0.0, Culture=neutral,
  3. PublicKeyToken=b77a5c561934e089"
  4. requirePermission="false" />
  5.  
  6. providerName="System.Data.SqlClient"
  7. connectionString="Data
  8. Source=YourSERVER;Initial Catalog=EfDBExistRepository;Integrated
  9. Security=True;MultipleActiveResultSets=True;"/>
  10.  

注意:数据库链接结点名为“DataContext”,正好和我们自己写的类“DataContext”名字一样。这样EF框架就可以自动找到这个数据库链接信息。

http://www.codeproject.com/Articles/561584/Repository-Pattern-with-Entity-Framework-using

你可能感兴趣的:(Repository模式--采用EF Fluent API使用EntityTypeConfiguration分文件配置Model映射关系)