基于非EF仓储模式的N层架构项目:跨UI统一读取配置需求
嘿,这个学校作业的需求挺明确的,咱们一步步拆解实现,保证满足所有要求:仓储模式、不依赖Entity Framework、N层架构、跨WPF/ASP.NET Core统一读取配置、支持多数据库。
一、整体架构分层设计
首先得把各层职责划清楚,核心是让配置读取和数据访问完全脱离UI层,架构分为5层:
- UI层:WPF(依赖
App.config)、ASP.NET Core 2.0网站(依赖appsettings.json)——只负责交互展示,不碰配置和数据逻辑 - 业务逻辑层(BLL):处理业务规则,依赖仓储层,通过接口调用数据服务
- 仓储层(Repository):实现数据访问逻辑,基于ADO.NET/Dapper(替代EF),支持多数据库
- 核心层(Core):提供统一的配置读取接口、数据库连接工厂、通用仓储接口——这是跨UI兼容的关键
- 实体层(Entities):数据库实体模型,各层共享的纯POCO类
二、跨UI统一配置读取实现
核心思路是:用接口抽象配置读取能力,针对WPF和ASP.NET Core分别实现,再通过依赖注入(DI)让底层层只依赖接口,不关心具体UI的配置源。
1. 定义统一配置接口(Core层)
在Core层创建IAppConfiguration,抽象所有配置读取操作:
public interface IAppConfiguration { // 根据名称获取数据库连接字符串 string GetConnectionString(string connectionName); // 可扩展其他配置项,比如日志级别、缓存超时等 }
2. 针对不同UI框架实现配置读取
(1)WPF端实现(适配App.config)
在WPF项目中创建WpfAppConfiguration,利用ConfigurationManager读取配置:
using System.Configuration; public class WpfAppConfiguration : IAppConfiguration { public string GetConnectionString(string connectionName) { return ConfigurationManager.ConnectionStrings[connectionName]?.ConnectionString; } }
(2)ASP.NET Core 2.0端实现(适配appsettings.json)
在ASP.NET Core项目中创建AspNetCoreAppConfiguration,利用框架自带的IConfiguration:
using Microsoft.Extensions.Configuration; public class AspNetCoreAppConfiguration : IAppConfiguration { private readonly IConfiguration _config; public AspNetCoreAppConfiguration(IConfiguration config) { _config = config; } public string GetConnectionString(string connectionName) { return _config.GetConnectionString(connectionName); } }
3. 依赖注入绑定配置实现
在各自UI层启动时,注册对应的配置实现,让底层层能通过接口拿到配置:
- WPF:用轻量DI容器(比如Autofac),在
App.xaml.cs的OnStartup中注册:
var containerBuilder = new ContainerBuilder(); // 注册配置实现为单例 containerBuilder.RegisterType<WpfAppConfiguration>().As<IAppConfiguration>().SingleInstance(); // 同时注册BLL、仓储层的服务 var container = containerBuilder.Build(); // 保存容器供全局使用
- ASP.NET Core 2.0:在
Startup.cs的ConfigureServices中注册:
services.AddSingleton<IAppConfiguration>(provider => new AspNetCoreAppConfiguration(provider.GetRequiredService<IConfiguration>())); // 注册其他业务、仓储服务
这样一来,BLL和仓储层只需要依赖IAppConfiguration,完全不用关心是WPF还是ASP.NET Core的配置源,彻底实现了解耦。
三、仓储模式与多数据库支持
不用EF的话,推荐用Dapper(轻量ORM,手写SQL灵活,适配多数据库)来实现仓储层。
1. 定义通用仓储接口与连接工厂(Core层)
先定义仓储的通用操作接口:
public interface IRepository<T> where T : class { IEnumerable<T> GetAll(); T GetById(int id); void Add(T entity); void Update(T entity); void Delete(T entity); }
再定义数据库连接工厂,用来创建不同类型的数据库连接:
public interface IDbConnectionFactory { IDbConnection CreateConnection(string connectionName); }
2. 实现多数据库连接工厂(Core层)
根据配置的连接字符串,判断数据库类型并创建对应连接(需要引用对应数据库的ADO.NET驱动,比如System.Data.SqlClient、MySql.Data.MySqlClient):
public class DbConnectionFactory : IDbConnectionFactory { private readonly IAppConfiguration _config; public DbConnectionFactory(IAppConfiguration config) { _config = config; } public IDbConnection CreateConnection(string connectionName) { var connectionString = _config.GetConnectionString(connectionName); // 根据连接字符串特征判断数据库类型,也可以在配置里额外指定DbType if (connectionString.Contains("SqlServer") || connectionString.Contains("Initial Catalog")) { return new SqlConnection(connectionString); } else if (connectionString.Contains("MySql") || connectionString.Contains("Uid")) { return new MySqlConnection(connectionString); } throw new NotSupportedException("当前不支持该数据库类型"); } }
3. 实现通用仓储基类(仓储层)
封装通用CRUD操作,避免重复代码:
public abstract class BaseRepository<T> : IRepository<T> where T : class { protected readonly IDbConnection _dbConnection; public BaseRepository(IDbConnectionFactory connectionFactory, string connectionName) { _dbConnection = connectionFactory.CreateConnection(connectionName); _dbConnection.Open(); } public IEnumerable<T> GetAll() { // 用Dapper执行查询,表名可根据实体类自定义 return _dbConnection.Query<T>($"SELECT * FROM {typeof(T).Name}"); } public T GetById(int id) { return _dbConnection.QueryFirstOrDefault<T>( $"SELECT * FROM {typeof(T).Name} WHERE Id = @Id", new { Id = id }); } public void Add(T entity) { // 实现插入逻辑,可根据实体属性生成SQL,或用Dapper的Insert扩展 _dbConnection.Execute("INSERT INTO ...", entity); } // Update、Delete方法类似实现,根据业务需求调整 public void Update(T entity) { /* ... */ } public void Delete(T entity) { /* ... */ } }
4. 针对特定数据库的仓储实现(可选)
如果某些数据库有特殊SQL语法,可以继承基类重写方法:
public class SqlServerUserRepository : BaseRepository<User> { public SqlServerUserRepository(IDbConnectionFactory connectionFactory) : base(connectionFactory, "SqlServerConnection") { } // 重写GetAll,添加SQL Server特有的NOLOCK优化 public override IEnumerable<User> GetAll() { return _dbConnection.Query<User>("SELECT * FROM Users WITH(NOLOCK)"); } }
四、配置文件示例
1. WPF的App.config
<configuration> <connectionStrings> <add name="SqlServerConnection" connectionString="Server=.;Database=SchoolDb;Integrated Security=True" /> <add name="MySqlConnection" connectionString="Server=localhost;Database=SchoolDb;Uid=root;Pwd=your_password" /> </connectionStrings> </configuration>
2. ASP.NET Core 2.0的appsettings.json
{ "ConnectionStrings": { "SqlServerConnection": "Server=.;Database=SchoolDb;Integrated Security=True", "MySqlConnection": "Server=localhost;Database=SchoolDb;Uid=root;Pwd=your_password" } }
五、关键注意事项
- 依赖注入是核心:通过DI注入
IAppConfiguration和IDbConnectionFactory,让各层解耦,方便单元测试和扩展新UI框架。 - SQL兼容性:尽量使用标准SQL,针对不同数据库的特殊语法,通过重写仓储方法来适配。
- 配置安全:生产环境不要硬编码敏感信息,WPF可以用DPAPI加密配置,ASP.NET Core可以用用户机密或密钥管理服务。
内容的提问来源于stack exchange,提问作者Dvg22

