DbContext,EF,& LINQ - 什么是通过接口在DbContext上公开方法的最佳方法?

时间:2012-03-19 17:56:51

标签: wcf entity-framework-4 interface extension-methods

我是EF和DBContext的新手,因此我正在寻找一些建议,以便使用EF,存储过程或SQL为WCF服务设置代码的最佳方式。

背景

我有一个MVC3前端,它连接到数据访问(Oracle)的WCF服务层。实际的数据访问是通过一个单独的DAO类库。

我的目标是让服务层仅使用一个接口,在该接口上它可以调用一组方法来返回数据。我不希望服务层意识到我们正在使用EF进行查询,因为我可以在需要时用存储过程或纯SQL文本替换慢速EF位。

目前我在哪里

我有一个用于我的数据库IDB的接口,以及一个同时实现DBContext的IDB,MyDB的混合实现。然后,MyDb有一些名为MyStdDB和MySecureDB的派生类。当我想要接口时,我调用我的工厂方法,如果我需要一个标准或安全的数据库,然后将其返回到我的接口变量中。

WCF代码:

public List<string> GetAccount() {
   IDB _db = DBFactory.GetInstance();
   return _db.GetAccount();
}

DBFactory代码:

 pubilc class DBFactory {
   pubilc static IDB GetInstance()
   {
     if bSecure
        return MySecureDB;
     else 
        return MyStdDB;
   }
 }

所以,当我想要查询时,我想在我的服务调用中询问_db.GetAccount()。目前我已将此作为IDB接口的扩展方法添加。这样做的原因是为了防止服务看到我的EF实体,它允许将qqueries转换为逻辑文件,例如。类充满了CUSTOMER查询,类充满了ACCOUNT查询。

IDB代码:

public interface IDB : IDisposable
{
    ObjectContext UnderlyingContext { get; }
    int SaveChanges();
}

MyDB代码:

public class MyDB : DbContext, IDB 
{
    ObjectContext IDB.UnderlyingContext
    {
        get
        {
            return ((IObjectContextAdapter)this).ObjectContext;
        }
    }

    int IDB.SaveChanges()
    {
        return SaveChanges();
    }       

    public DbSet<Customer> Customer { get; set; }
}

扩展方法:

public static List<string> GetAccount(this IDB _db)
{
    ((MyDB)_db).Customer.AsNoTracking().First();
}

问题

正如您所看到的,我必须将接口转换为具体对象,以便我可以访问EF实体。这是因为实体是在实现类而不是接口。 Extension方法在我的DAO类库中,因此当我的IDB implmentation改变时会改变,但我仍然不喜欢它。 有更好的方法吗?我在看DI吗?

对我来说,最大的推动力是:

  • 只能通过接口访问数据库,因为我们可能很快就会更换数据库。
  • 必须从服务中隐藏数据访问方法。我应该只能通过接口/扩展方法等提供的方法访问数据。

1 个答案:

答案 0 :(得分:2)

解决方法是将您的GetAccount移至IDB,而不是使用扩展程序:

public interface IDB : IDisposable
{
    ObjectContext UnderlyingContext { get; }
    List<string> GetAccount();
    int SaveChanges();
}

它解决了您的问题,因为MyDB将实现该方法,并且所有派生类也将使用实现。如果他们提供其他实现,他们将简单地覆盖它。

  

必须从服务中隐藏数据访问方法。我应该只   能够通过提供的方法访问数据   接口/扩展方法等。

但他们不是。如果方法/属性不公开,则隐藏该方法/属性,但目前您的任何服务都可以将IDB转换为MyDB并直接访问DbSet