65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 EntityTypeConfiguration 的 Entity Framework 存储库模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (18投票s)

2013年3月14日

CPOL

3分钟阅读

viewsIcon

134766

downloadIcon

42328

使用 EntityTypeConfiguration 的 Entity Framework 存储库模式

引言

我一直在寻找使用 Entity Framework Code First 和 EntityTypeConfiguration 的仓储模式的集成示例,但未能找到。在此,我只涉及基础知识。这是我的第一篇文章。

背景

为了使本文简单易懂,我使用了两个简单的对象:CategoryProduct

我使用 EntityTypeConfiguration 来实现不同层与数据库的交互以及字段验证。

以下是解决方案的结构树。

**注意:我们需要在 EfRepPatTest.Data 项目中添加 Entity Framework 引用。

开发工具

  • VS 2010
  • Entity Framework 库

Using the Code

首先,我们将在解决方案中创建三个项目,其中两个是类库,另一个是用于实现的控制台项目。

解决方案名称 EfRepositoryPatterTest
类库名称 EfRepPatTest.Entity
EfRepPatTest.Data
控制台应用程序 EfRepPatTest.Implementation

EfRepPatTest.Entity 项目中,我们将创建以下类

BaseEntity.cs

public class BaseEntity<T>
{
    public T Id { get; set; }
}

IRepository.cs [接口]

其中包含以下操作

public interface IRepository<TEntity> where TEntity:class 
{
    IQueryable<TEntity> GetAll();
    TEntity GetById(object id);
    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

Category.cs

它将继承 BaseEntity 类以获取 Id 属性并将 Id 字段指定为整数。

public class Category:BaseEntity<int>
{
    public virtual string Name { get; set; }

    public List<Product> Products { get; set; }
}

Product.cs

category 类相同。

public class Product:BaseEntity<long>
{
    public virtual int CategoryId { get; set; }
    public virtual Category Category { get; set; }
    public virtual string Name { get; set; }
    public virtual int MinimumStockLevel { get; set; }
}

EfRepPatTest.Data 项目包含以下类或接口。

在此项目中添加 EntityFrameworkEfRepPatTest.Entity 的引用。

首先,创建一个驱动 DbContext 类的接口,即 DataContext 类将使用的接口。

IDbContext.cs

public interface IDbContext
{
    IDbSet<TEntity> Set<TEntity>() where TEntity:class;
    int SaveChanges();
    void Dispose();
}

此处,IDbSet 接口属于 System.Data.Entity 命名空间。创建一个名为 DataContext 的类,该类将继承 DbContext 并使用 IDbContext

DataContext.cs [部分]

public class DataContext: DbContext,IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }
}

在讨论 DataContext 类的功能之前,我们需要另外两个类,它们将 EntityEntityTypeConfiguration 进行映射,并保存数据库表的 Field Validation 逻辑。

创建文件夹名 "Mapping",并将 CategoryMapProductMap 类放在其中 [可选]。

CategoryMap.cs

public class CategoryMap:EntityTypeConfiguration<Category>
{
    public CategoryMap()
    {
        ToTable("Category");
        HasKey(c => c.Id).Property
              (c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(c => c.Name).IsRequired().HasMaxLength(50);
    }
}

ProductMap.cs

public class ProductMap:EntityTypeConfiguration<Product>
{
    public ProductMap()
    {
        ToTable("Product");
        HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption
              (DatabaseGeneratedOption.Identity);
        //CategoryId as foreign key
        HasRequired(p => p.Category)
            .WithMany(c=>c.Products)
            .HasForeignKey(p => p.CategoryId);
        Property(p => p.Name).IsRequired().HasMaxLength(100);
        Property(p => p.MinimumStockLevel);
    }
}

以上部分将帮助我们避免直接使用 Entity [ProductCategory] 作为数据库表,而是涵盖数据库表逻辑和验证。

现在,在 DataContext 类中添加 "OnModelCreating" 方法,用于将 Entity 作为模型的一部分附加。以下代码片段将演示如何手动配置由 EntityTypeConfiguration 驱动的类 [ProductMap, CategoryMap] 与 ModelBuilder

{
    modelBuilder.Configurations.Add(new CategoryMap());
    modelBuilder.Configurations.Add(new ProductMap());
    base.OnModelCreating(modelBuilder);
}

这里的问题是所有类都需要手动配置。因此,我希望避免这样做。以下代码将帮助我们自动完成此操作。

DataContext.cs [完整]

public class DataContext: DbContext,IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
        .Where(type => !String.IsNullOrEmpty(type.Namespace))
        .Where(type => type.BaseType != null && type.BaseType.IsGenericType && 
           type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
        foreach (var type in typesToRegister)
        {
            dynamic configurationInstance = Activator.CreateInstance(type);
            modelBuilder.Configurations.Add(configurationInstance);
        }

        base.OnModelCreating(modelBuilder);
    }
}

我们尚未实现 IRepository 接口,通过 RepositoryService 类,我们将实现它。

RepositoryService.cs

public class RepositoryService<TEntity>:IRepository<TEntity> where TEntity:class 
{
    private IDbContext Context;

    private IDbSet<TEntity>  Entities
    {
        get { return this.Context.Set<TEntity>(); }
    }

    public RepositoryService(IDbContext context)
    {
        this.Context = context;

    }

    public IQueryable<TEntity> GetAll()
    {
        return Entities.AsQueryable();
    }

    public TEntity GetById(object id)
    {
        return Entities.Find(id);
    }

    public void Insert(TEntity entity)
    {
        Entities.Add(entity);
    }

    public void Update(TEntity entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");

        this.Context.SaveChanges();
    }

    public void Delete(TEntity entity)
    {
        Entities.Remove(entity);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (this.Context != null)
            {
                this.Context.Dispose();
                this.Context = null;
            }
        }
    }
}

"private IDbSet<TEntity> Entities" 属性将返回 DbSet 实例,以便在上下文中访问给定类型的实体。

现在,您需要一个用于初始化数据库的类。添加一个名为 DataBaseInitializer 的类。

DataBaseInitializer.cs

public class DataBaseInitializer : IDatabaseInitializer<DataContext>
{
    public void InitializeDatabase(DataContext context)
    {
        context.Database.CreateIfNotExists();
    }
}

通过 EfRepPatTest.Implementation 控制台项目实现应用程序

Program.cs 类如下所示

class Program
{
    static void Main(string[] args)
    {
        var context = new DataContext();
        var dataBaseInitializer = new DataBaseInitializer();
        dataBaseInitializer.InitializeDatabase(context);

        var categoryRepository = new RepositoryService<Category>(context);

        //Adding category in the category entity
        var category = new Category()
        {
            Name = "Baverage"
        };
        var products = new List<Product>();

        //Adding product in the product entity
        var product = new Product()
            {
                Name = "Soft Drink A",
                MinimumStockLevel = 50
            };
        products.Add(product);

        product = new Product()
        {
            Name = "Soft Drink B",
            MinimumStockLevel = 30
        };
        products.Add(product);

        category.Products = products;

        //Insert category and save changes
        categoryRepository.Insert(category);
        context.SaveChanges();

        ///////////////////////////////////////////////////////////////////////////////
        /////////////////For the next project we shall add Dependency Injection////////
        ////////////////But now we have add a Service layer for test manually//////////
        ///////////////////////////////////////////////////////////////////////////////
        IProductService productRepository = new ProductService();

        Console.WriteLine("\n");
        Console.WriteLine("Product List:");
        Console.WriteLine("-------------------------------------------------");
        foreach (var product1 in productRepository.GetAll())
        {
            Console.WriteLine(string.Format("Product Name : {0}",product1.Name));
            if (product1.Id == 9)
            {

                product1.Name = "Soft Drink AAA";
                productRepository.Update(product1);
            }
        }
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
}

在此,我们添加了 "EfRepPatTest.Service" 项目来测试服务。这将在下一篇文章中有所帮助。

App.config 中的连接字符串 [高亮部分]

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information
on Entity Framework configuration, visit
http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" 
             type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection,
EntityFramework, Version=4.4.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" 
             requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory,
EntityFramework" />
  </entityFramework>

  <connectionStrings>
      <add name="DataContext" 
         providerName="System.Data.SqlClient" 
         connectionString="Data
Source=YourSERVER;Initial Catalog=EfDBExistRepository;Integrated
Security=True;MultipleActiveResultSets=True;"/>
 
  </connectionStrings>
</configuration>

连接字符串的名称 [name="DataContext"]DataContext.cs 类相同,它将自动工作。

希望有所帮助!

下一篇文章

历史

  • 2013 年 3 月 20 日:初始版本
© . All rights reserved.