我有两个不同的工作单元:一个基于 ADO.NET ,主要调用存储过程(uowADO
),另一个使用 Entity Framework 6 (uowEF
),最近添加了以支持 Oracle db,因此我不必重写所有SP(我的知识在那里有限)。
因此,在对数据库执行操作时,业务层只加载其中一个(基于配置)(但我无法并行使用它们,因为uowADO
不支持Oracle)
添加新的uowEF
后,我注意到了大的性能问题,当然主要是批量操作。
基本上我现在只有Commit
和Rollback
方法在当前IUnitOfWork
...非常接近article推荐的方法。
所以,我正在考虑重做这个工作单元。例如,我读到了有时在涉及批量操作时禁用dbContext.Configuration.AutoDetectChangesEnabled
,以及有关 EF 的其他此类优化提示可能有所帮助。
不幸的是,我不确定如何设计这样的工作单元以使其通用,以便我可以在BL和所有数据访问层的所有情况下使用它: ADO.NET 和 EF
有任何想法,建议和良好的链接吗?
答案 0 :(得分:1)
不幸的是,我不确定如何设计这样的工作单元来实现它 通用,这样我就可以在BL和两种数据的所有情况下使用它 访问层:ADO.NET和EF。
首先要意识到EF无法访问数据库。它依赖于ADO.NET。最后,它使用命令,数据引导等来完成低级别的工作。
以一种可以在EF上下文中提取连接然后直接使用ADO.NET的方式进行设置是微不足道的。
由于EF无论如何都无法以高效率进行高效的批量操作 - 您无论如何都必须依赖ADO.NET。从SQL的角度来看,EF本身就是如何处理大容量数据库的完美反例。它每行使用一次更新/插入 - 尽管(例如,甚至忽略了SqlBulkCopy)它可以为大多数数据库发出一个多行,因为语法完全允许。
正如它所说的那样:当您喜欢阅读样本文档时,访问底层连接非常简单。这是我用于批量插入的代码。 ObjectBulkCopy类稍微复杂一些,但是在这里可以看到如何获取数据库连接:
public static void BulkInsert<T>(this Repository repository, IEnumerable<T> objects) where T : class
{
var bulkCopy = new ObjectBulkCopy<T>();
var connection = (SqlConnection) repository.Database.Connection;
bulkCopy.Insert (objects, connection);
}
非常简单 - 它在任何存储库中都是属性,可以进行转换。
答案 1 :(得分:1)
没有明确的答案。它始终是灵活性和性能之间的折衷。所有这些模式(存储库,工作单元)都有利于灵活性,但不是性能,因为具体实现通常需要进行一些调整以提供最大性能,并且这些调整可能(实际上它们不会)与通用接口兼容。您可以调整界面,但它可能无法与其他实现一起使用。所有这些ORM都非常不同,实现通用存储库/ UOF接口以支持所有这些ORM非常困难(几乎不可能),特别是如果你有ADO(低级ORM,实际上很难称之为ORM)和EF(高水平的ORM)。将AutoDetectChangesEnabled设置为false只是您可以使用EF执行的一小部分。要从中获得更多性能,还必须以特定方式实现enities(添加一些属性,一些属性)。如果我们查看Linq2Sql(另一个ORM),它需要编译查询,所以,忘记这样的方法:
T Single(Expression<Func<T, bool>> predicate);
在您的存储库中。我只是谈论关系数据库的存储库。 NoSql数据库的存储库怎么样?基于完全不同的数据源的存储库怎么样?是的,可以提供具有通用逻辑的通用接口,但对于某些数据源来说它会非常慢。如果您真的想要实现通用解决方案并获得最大性能,那么UOF的存储库应该具有非常具体的界面,如:
IEnumerable<T> GetStudentsByName(srting name)
void InsertStudents<T>(IEnumerable<T> students)
其中T - 不应依赖于具体存储库实现的业务级实体。存储库应负责将T转换为接受其实现访问的ORM的实体。但请记住,解决方案太复杂且难以支持。
如果我是你,我会选择一个最符合我要求的主要ORM,并设计围绕此ORM的存储库以获得最大的性能。但是,我将保持界面足够灵活,以便至少实现对其他数据源或ORM的缓慢(但有效)访问。