如何在EF中使用存储库模式使用存储过程和复杂类型?

时间:2012-01-23 02:23:07

标签: c# entity-framework repository repository-pattern

我们如何在实体框架中处理存储库模式时使用存储过程和复杂类型?有人可以给出一个简单的例子。

同样在什么情况下我们应该采用Repository模式?

提前致谢

2 个答案:

答案 0 :(得分:14)

我认为当EF已经通过ObjectSet / DbSet实现存储库模式时,你错过了为什么人们实现存储库模式的一点?

热门答案是因为许多教程建议您在没有正当理由的情况下使用它。 不使用存储库层超过ObjectSet / DbSet是有正当理由的。但是,我会指出一些原因,为什么它更适合。

默认过滤器 在现实生活中,您需要一个默认过滤器的情况很多。例如,不销售已停产的产品。如果直接公开Products ObjectSet / DbSet,如果有人忘记应用默认过滤器,则会出现问题。它还避免了逻辑的重复。您也可以稍后修改默认过滤器,而不会破坏问题。

public IQueriable<Product> GetAll()
{
    return context.Products.Where(p => !p.IsDiscontinued);
}

软删除 许多应用程序使用软删除,您可以保留IsDeleted之类的列而不实际删除该行。现在ObjectSet / DbSet有一个Delete方法,但是一旦调用此方法,它就会将null值赋给可空的FK属性。你可能不想要这个。

public void Delete(Product product)
{
    // can apply any other logic here
    product.IsDeleted = true;
}

只读实体 在许多情况下,其他一些应用程序负责创建,删除和更新实体,而您的应用程序仅显示实体。但在这种情况下,ObjectSet / DbSet公开了不受支持的功能。在这种情况下,另一个好处是使用NoTracking选项来减少实体实现时间。

切换数据访问而不暴露实现有时候LINQ是不够的。在这里,您可以使用原始SQL或SP。拥有存储库将避免在EF公开的功能不足时暴露不同的查询/更新方法。

使用现有数据库 如果您没有创建EF能够处理的数据库的奢侈。现有表格可能包含Sql VariantXML列。将条目复制到另一个表以及为了保持数据库的完整性而需要处理的无数其他情况。

这些技术可能不是防弹的,但如果情况需要它会派上用场。我建议不要直接跳到存储库,你最好考虑添加另一个抽象层来实现所需的功能。

答案 1 :(得分:2)

存储库模式对于将数据存储机制与应用程序分离非常重要。通过这样做,您可以更轻松地在以后进行单元测试或替换数据结构。请阅读我的博客文章,了解我为何/为何在此处执行此操作:http://blog.staticvoid.co.nz/2011/10/staticvoid-repository-pattern-nuget.html

我个人从不再使用存储过程,因为在大多数情况下我并不真正看到它们,但是为了用我的存储库模式实现这个,我建议你创建一个新的RepositoryDataSource来映射到你的存储过程和然后通过EF或旧学校SQL调用存储的进程。我建议在更新或保存时抛出某种异常。

==编辑(回答'为什么2层'的问题')==

我选择选择两层的原因是因为在我看来,存储库与你如何获取数据(数据源层)以及如何呈现图层有关(在我的实现中,可能很糟糕)命名存储库)。通过将实现分成两半,无论如何都可以保持相同。相反,如果你想改变你如何做到这一点,同时保持松散地耦合到什么。

例如,您可能希望将EF数据源交换为内存版本。这不一定会改变数据呈现给应用程序的方式。

另一方面,您可能希望缓存数据或预先记录一些有关写入数据存储区性能的信息。为什么在封面下使用实际的存储机制至关重要?

就我个人而言,我已经在这个特定的地方找到了分裂,使解决方案更加灵活。