Entity Framework 4.1通用储存库设置 [英] Entity Framework 4.1 Generic Repository set up

查看:228
本文介绍了Entity Framework 4.1通用储存库设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Entity Framework的新手,并加入了一个使用通用资源库的项目,如下所示。存储库设置的方式有什么缺点?我注意到,大多数教程都描述了基于通用基本存储库创建多个存储库,而不是具有处理所有内容的一个通用存储库。

为了给出一些背景,这段代码是ASP.NET MVC 3网站的一部分,我们使用unity作为IOC容器。业务层中的所有组件都继承自通过构造函数注入IEntityRepository的基类。



这是通用的资源库类

  public class MyRepository 
{
private const string containerName =myEntities;
private readonly ObjectContext上下文;
private只读Hashtable objectSets;

//跟踪Dispose是否被调用。
私人布尔处置;

MyRepository()
{
string connectionString = ConfigurationManager.ConnectionStrings [containerName] .ConnectionString;

context = new ObjectContext(connectionString){DefaultContainerName = containerName};
context.ContextOptions.LazyLoadingEnabled = true;
context.ContextOptions.ProxyCreationEnabled = true;

objectSets = new Hashtable();
}

private ObjectSet< TEntity> GetObjectSet< TEntity>()其中TEntity:class
{
ObjectSet< TEntity>对象集;

var type = typeof(TEntity);
if(objectSets.ContainsKey(type))
{
objectSet = objectSets [type] as ObjectSet< TEntity>;
}
else
{
objectSet = context.CreateObjectSet< TEntity>();
objectSets.Add(type,objectSet);
}

返回objectSet;
}

public IQueryable< TEntity> GetAll< TEntity>(params string [] entities)其中TEntity:class
{
ObjectQuery< TEntity> objectQuery = GetObjectSet< TEntity>();

foreach(实体中的实体)
{
objectQuery = objectQuery.Include(entity);
}

返回objectQuery;


$ b public void Insert< TEntity>(TEntity entity)其中TEntity:class
{
ObjectSet< TEntity> objectSet = GetObjectSet< TEntity>();
objectSet.AddObject(entity);
}

public void Update< TEntity>(TEntity entity)其中TEntity:class
{
ObjectSet< TEntity> objectSet = GetObjectSet< TEntity>();

EntityKey key = objectSet.Context.CreateEntityKey(objectSet.EntitySet.Name,entity);

object originalItem;
if(objectSet.Context.TryGetObjectByKey(key,out originalItem))
{
objectSet.ApplyCurrentValues(entity);
}
else
{
objectSet.Attach(entity);
objectSet.ApplyCurrentValues(entity);


$ b $ public void删除< TEntity>(TEntity entity)其中TEntity:class
{
ObjectSet< TEntity> objectSet = GetObjectSet< TEntity>();
objectSet.DeleteObject(entity);


public void SaveChanges()
{
try
{
context.SaveChanges();

catch(Exception ex)
{
ex.ToString();
throw ex;



public void Dispose()
{
Dispose(true);
//将自己关闭到Finalization队列
//以防止此对象的终止代码
//第二次执行。
GC.SuppressFinalize(this);


protected virtual void Dispose(bool disposing)
{
//检查Dispose是否已被调用
if(!dispose)
{
if(disposing)
{
context.Dispose();
}
}
disposed = true;
}

〜MyRepository()
{
Dispose(false);






$ b这是用于公开方法的接口: / p>

  public interface IEntityRepository:IDisposable 
{
删除< TEntity>(TEntity entity)其中TEntity:class ;

IQueryable< TEntity> GetAll< TEntity>(params string [] entities)其中TEntity:class;

void插入< TEntity>(TEntity entity)其中TEntity:class;

更新< TEntity>(TEntity实体)其中TEntity:class;

void SaveChanges();


解决方案

使用通用存储库,而不是每个集合根具有一个具体的存储库实现,是你不能为特定用途创建特定的方法。

让所有的存储库从一个基本存储库继承,让你创建如下的方法: GetProductsInsSock()或像 UpdateOnlyProductsThatSatisfySomething()



但有些解决方法可用! ; - )

如果它适合您的团队,请继续使用您的通用存储库,您可能需要添加的唯一方法是接受规格作为参数。正如Eric Evans和Martin Fowler所说:


规范的核心思想是将
如何与候选人匹配,从匹配
的候选对象。


在你的情况下,它可以作为一个过滤器来检索而不需要创建特定的方法。



您可以简单地将它添加到您的 IRepository 界面中:

  IEnumerable< T>查找(规范< T>谓词); 

您的 Repository 类中的方法实现将会如下所示:

  public class Repository< T> :IRepository< T>其中T:class 
{
public Repository(IDbContext context)
{
_context = context;
_dbset = context.Set< T>();
}

//一些代码...

public IEnumerable< T> Find(Specification< T> specification)
{
return _dbset.Where(specification.Predicate);
}

//一些代码...
}

规范类可能如下所示:

  public类规范< T> 
{
public Specification(Expression< System.Func< T,bool>>谓词)
{
_predicate = predicate;
}

内部表达式< System.Func< T,bool>> Predicate
{
get {return _predicate; }
}

private readonly表达式< System.Func< T,bool>> _谓词;
}

一个调用示例:

  var规格= ProductSpecification.InStock(); 
var product = Repository.Find(specification).FirstOrDefault();

最后, ProductSpecification 类:

 内部静态类ActionSpecification 
{
internal static Specification< Product> InStock()
{
return new Specification< Product>(p => p.IsInStock == true);
}
}


I'm new to Entity Framework and joined a project that uses a generic repository as shown below. Are there any disadvantages to the way the repository is set up? I've noticed that most tutorials describe creating multiple repositories based on a generic base repository rather than having one generic repository that handles everything.

To give some background this code is part of an ASP.NET MVC 3 website and we're using unity as an IOC container. All of the components in the business layer inherit from a base class that has has the IEntityRepository injected via the constructor.

This is the generic repository class

public class MyRepository
{
    private const string containerName = "myEntities";
    private readonly ObjectContext context;
    private readonly Hashtable objectSets;

    // Track whether Dispose has been called.
    private bool disposed;

    public MyRepository()
    {
        string connectionString = ConfigurationManager.ConnectionStrings[containerName].ConnectionString;

        context = new ObjectContext(connectionString) {DefaultContainerName = containerName};
        context.ContextOptions.LazyLoadingEnabled = true;
        context.ContextOptions.ProxyCreationEnabled = true;

        objectSets = new Hashtable();
    }

    private ObjectSet<TEntity> GetObjectSet<TEntity>() where TEntity : class
    {
        ObjectSet<TEntity> objectSet;

        var type = typeof (TEntity);
        if (objectSets.ContainsKey(type))
        {
            objectSet = objectSets[type] as ObjectSet<TEntity>;
        }
        else
        {
            objectSet = context.CreateObjectSet<TEntity>();
            objectSets.Add(type, objectSet);
        }

        return objectSet;
    }

    public IQueryable<TEntity> GetAll<TEntity>(params string[] entities) where TEntity : class
    {
        ObjectQuery<TEntity> objectQuery = GetObjectSet<TEntity>();

        foreach (var entity in entities)
        {
            objectQuery = objectQuery.Include(entity);
        }

        return objectQuery;
    }


    public void Insert<TEntity>(TEntity entity) where TEntity : class
    {
        ObjectSet<TEntity> objectSet = GetObjectSet<TEntity>();
        objectSet.AddObject(entity);
    }

    public void Update<TEntity>(TEntity entity) where TEntity : class
    {
        ObjectSet<TEntity> objectSet = GetObjectSet<TEntity>();

        EntityKey key = objectSet.Context.CreateEntityKey(objectSet.EntitySet.Name, entity);

        object originalItem;
        if (objectSet.Context.TryGetObjectByKey(key, out originalItem))
        {
            objectSet.ApplyCurrentValues(entity);
        }
        else
        {
            objectSet.Attach(entity);
            objectSet.ApplyCurrentValues(entity);
        }
    }

    public void Delete<TEntity>(TEntity entity) where TEntity : class
    {
        ObjectSet<TEntity> objectSet = GetObjectSet<TEntity>();
        objectSet.DeleteObject(entity);
    }

    public void SaveChanges()
    {
        try
        {
            context.SaveChanges();
        }
        catch (Exception ex)
        {
            ex.ToString();
            throw ex;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        // Take yourself off the Finalization queue 
        // to prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called
        if (!disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        disposed = true;
    }

    ~MyRepository()
    {
        Dispose(false);
    }
}

This is the interface used to expose the methods:

public interface IEntityRepository : IDisposable
{
    void Delete<TEntity>(TEntity entity) where TEntity : class;

    IQueryable<TEntity> GetAll<TEntity>(params string[] entities) where TEntity : class;

    void Insert<TEntity>(TEntity entity) where TEntity : class;

    void Update<TEntity>(TEntity entity) where TEntity : class;

    void SaveChanges();
}

解决方案

The main disadvantage of using a generic repository instead of having a concrete repository implementation per Aggregate root, is that you cannot create specific methods for specific usages.

Having all your repositories inherit from a base repository let you create methods like: GetProductsInsSock() or things like UpdateOnlyProductsThatSatisfySomething().

But some workarounds are available! ;-)

Keep on using your generic repository if it suits to your team, the only thing you might have to add is a method that accept a Specification as parameter. As Eric Evans and Martin Fowler say:

The central idea of Specification is to separate the statement of how to match a candidate, from the candidate object that it is matched against.

In your case it could work as a filter to retrieve the right entities without having the need to create a specific method.

You could simply add this to your IRepository interface:

IEnumerable<T> Find(Specification<T> predicate);

The method implementation in your Repository class would be like this:

public class Repository<T> : IRepository<T> where T : class
{
  public Repository(IDbContext context)
  {
    _context = context;
    _dbset   = context.Set<T>();
  }

  // some code...

  public IEnumerable<T> Find(Specification<T> specification)
  {
    return _dbset.Where(specification.Predicate);
  }

  // some code...
}

The Specification class could look like this:

public class Specification<T>
{
  public Specification(Expression<System.Func<T, bool>> predicate)
  {
    _predicate = predicate;
  }

  internal Expression<System.Func<T, bool>> Predicate
  {
    get { return _predicate; }
  }

  private readonly Expression<System.Func<T, bool>> _predicate;
}

A call example:

var specification = ProductSpecification.InStock();
var product = Repository.Find(specification).FirstOrDefault();

And finally, the ProductSpecification class:

internal static class ActionSpecification
{
  internal static Specification<Product> InStock()
  {
    return new Specification<Product>(p => p.IsInStock == true);
  }
}

这篇关于Entity Framework 4.1通用储存库设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆