Antler:.NET 中你喜欢的 ORM 抽象 (第一部分)






4.77/5 (15投票s)
使用相同的语法来处理不同的 ORM。
引言
在某个时候,我们意识到在开发各种 .NET 项目时,我们会不时地重复做一些类似的事情。通常,我们的项目具有以下共同点:
- 使用某个 ORM 以 Code First 的方式与数据库交互。
- 使用某个 IoC 容器。
- 以某种方式使用 UnitOfWork/Repository 模式。
- 拥有解耦的架构和良好的可测试性。
因此,我们决定实现一个完全可插拔的开源框架,使用相同的语法来处理流行的 ORM。
现在,包括瑞银投资银行在内的几家主要组织都在使用这个框架。也许其他人也会觉得它有用,甚至会有兴趣为其贡献力量。
请将本文视为对 Antler 框架的初步介绍。
框架目标
- 使用通用的语法来处理不同的 ORM,这样我们就可以轻松地替换一个 ORM。
- 拥有非常简单的“流畅”配置。
- 完全可插拔。例如,选择使用哪个 ORM、IoC 容器或数据库应该非常容易。
- 使用该框架的应用程序应该是可轻松测试的(单元测试和集成测试)。
概念解释
ORM 抽象
核心思想是拥有统一的语法来处理任何 ORM。这是通过完全解耦的风格来实现 UnitOfWork、Generic Repository 等模式的。
统一的语法提供了无痛切换不同 ORM 的能力:你只需要更新应用程序引导程序中的一行配置,并更新实体的映射。即使你未来不打算切换 ORM,这种 ORM-无关的架构也会使你的代码更清晰。
配置非常简单,下面的示例展示了如何配置应用程序以使用 EntityFramework ORM 和 Castle Windsor 容器
var configurator = new AntlerConfigurator();
configurator.UseWindsorContainer()
.UseStorage(EntityFrameworkStorage.Use.WithConnectionString(connectionString).
WithMappings(assemblyMithMappings));
然后,您就可以使用统一的语法来处理数据库。例如,在数据库中插入数据:
UnitOfWork.Do(uow =>
{
uow.Repo<Team>().Insert(new Team() {Name = "Penguins", Description = "Hockey"});
uow.Repo<Team>().Insert(new Team() {Name = "Capitals", Description = "Hockey"});
uow.Repo<Team>().Insert(new Team() {Name = "Nets", Description = "Basketball"});
});
从数据库查询
var found = UnitOfWork.Do(uow => uow.Repo<Team>().AsQueryable().
Where(t => t.Description == "Hockey").
OrderBy(t => t.Name).ToArray());
UnitOfWork 在这里代表了底层数据库事务的包装器。Generic Repository 提供了 IQueryable 接口来查询数据库,并提供了一组标准操作,如 Insert、Delete 等。
但是,如果出于某些原因需要使用 ORM 特有的语法,当然,你可以访问“内部” ORM 的会话。当需要执行某些不适合统一 Antler 语法的 ORM 特有操作时,你可能需要这样做。
例如,你可以访问“内部” NHibernate 会话 ISession 并使用 NHibernate 的 QueryOver 方法,如下所示
UnitOfWork.Do(uow =>
{
var internalSession = uow.SessionScope.GetInternal<ISession>();
var result = internalSession.QueryOver<Team>().Where(t => t.Name == "Awesome")
.List();
//do something with result
});
目前,Antler 框架支持 NHibernate、EntityFramework 和 Linq2Db 这三种 ORM。
IoC 抽象
IoC 容器在 Antler 框架中也有其抽象。在应用程序的引导程序中安装你喜欢的容器后,你的代码中就没有对其的依赖了。所有与容器的工作都通过 IContainer 接口完成,该接口看起来像这样:
public interface IContainer
{
T Get<T>();
T Get<T>(string name);
objectGet(Type type);
object Get(Type type, string name);
IList<T> GetAll<T>();
IList GetAll(Type type);
void Release(object instance);
void Put(IBindingSyntax binding);
bool Has<T>();
bool Has(Type type);
bool Has<T>(string name);
bool Has(Type type, string name);
}
下面的示例展示了如何配置应用程序以使用 StructureMap 容器以及 NHibernate + SqlServer
var configurator = new AntlerConfigurator();
configurator.UseStructureMapContainer()
.UseStorage(NHibernateStorage.Use.WithDatabaseConfiguration(MsSqlConfiguration.
MsSql2008.ConnectionString(connectionString)).
WithMappings(assemblyWithMappings));
目前,Antler 框架支持 Castle Windsor 和 StructureMap 这两种 IoC 容器。
顺便说一下,非常感谢 Kostassoid 完成了这一部分。
可测试性
如前所述,Antler 框架的目标是提供轻松切换 ORM、IoC 和数据库的能力。这在编写功能集成测试时非常有用,因为你可以轻松地配置测试环境。
例如,如果你的应用程序使用 NHibernate + Oracle,你可能会在引导程序中有以下配置:
var configurator = new AntlerConfigurator();
configurator.UseWindsorContainer()
.UseStorage(NHibernateStorage.Use.WithDatabaseConfiguration(
OracleDataClientConfiguration.Oracle10.ConnectionString(connectionString).
DefaultSchema(dbSchemaName)).WithMappings(assemblyWithMappings));
然后,你可能不想为集成测试创建一个另一个臃肿的 Oracle 数据库。相反,你可以配置你的测试项目使用 NHibernate + Sqlite 内存数据库。在这种情况下,你的测试项目将使用与你的应用程序相同的 ORM 映射,但数据库不同。
var configurator = new AntlerConfigurator();
configurator.UseWindsorContainer()
.UseStorage(NHibernateStorage.Use.WithDatabaseConfiguration(SQLiteConfiguration.
Standard.InMemory()).WithMappings(assemblyWithMappings));
可插拔结构
框架以“可插拔”风格实现。“Antler.Core”项目包含所有抽象和共享功能。还有其他项目(适配器)包含具体的实现。例如,NHibernate ORM 或 Castle Windsor IoC 容器的适配器。
因此,如果我们想在项目中使用 NHibernate 作为 ORM,Castle Windsor 作为 IoC 容器,那么我们需要从 NuGet 安装 Antler.Core 主库和 Antler.NHibernate/Antler.Windsor 适配器。然后,如果我们决定更改 ORM,例如,从 NHibernate 更改为 EntityFramework,那么我们只需要从 NuGet 替换 Antler.NHibernate 适配器为 Antler.EntityFramework。
类似地,如果需要,我们可以更改 IoC 容器适配器(例如,从 Antler.Castle 更改为 Antler.StructureMap)。
目前,有 NHibernate、EntityFramework、Linq2Db 的 ORM 适配器,以及 Castle Windsor 和 StructureMap 的 IoC 适配器。
结论
尽管 Antler 框架已被投入生产使用,但未来还有大量工作要做。我们计划添加对其他流行 IoC 容器的适配器,并且有一个雄心勃勃的想法是将 Antler 框架适配到 NoSql 解决方案(MongoDb 等)。
非常欢迎贡献。 如果您有兴趣,可以在 GitHub 上找到项目页面。
如果您只想尝试一下这个框架,您可以轻松地从 NuGet 安装它:
核心库,以及 NHibernate、EntityFramework、Linq2Db, Castle Windsor、StructureMap 的适配器。
如果您在安装/使用过程中遇到问题或有任何疑问,请告诉我。感谢您的关注。