-- sdmap:比EF可控,比 Mybatis轻量, 比拼接sql友好的ORM/Sql管理方案
【官网】:https://github.com/sdcb/sdmap
应用场景
通常情况下,.net开发场景下,涉及sql时,如果使用ef框架,则有些sql最终生成什么样可能和预期不一样。 而mybatis,ibatis这些框架要么很久没有维护,要么只支持.net framework 而不支持.net core, 要么xml语法相对比较臃肿。 另外直接在代码中拼接sql字符串又显得很难维护。 涉及改动之类的时候容易出错。基础资源
.net core/.net framework, sdmap.dll,sdmap.ext.dll,antlr4.dll
使用须知
注意部署环境,注意.sdmap的资源文件的属性(内嵌),否则将无法随程序发布。
配置步骤
【概述: 为什么推荐使用sdmap来管理项目中的sql?】
- 非常简单的语法来描述动态SQL;
- 使用了Emit CIL来确保性能;
- 有Visual Studio插件支持,实现了代码高亮、代码折叠、快速导航的特性;
- 支持所有主流数据库,如MySQL、SQL Server、SQLite等(只要Dapper能支持);
- 可以扩展支持非关系型数据库,如Neo4j
- 同时支持.net framework, .net core. //这一点比mybatis,ibatis都要好。
【使用示例】
<step1: 在.sdmap文件中配置一个简单的sql>
<step2: 在代码中调用上述sql并使用ORM自动映射为对象>
【注】上述 _db就是 IDbConnection对象的实现,可以是MySqlConnection之类的。
常见问题
-
sdmap中的sql明明正常,但提示sql某处错误
【解决方案】sdmap官方存在一个漏洞,它使用不当会加载多个程序集目录下sdmap资源,如果namespace和sql名相同则会覆盖 -
部分sdmap的sql正常,但另外一些提示对象为null异常
【解决方案】排查where条件中字段名是否存在,不存在会报null错误,但不会给出具体描述 -
编译发布后sdmap文件丢失了
【解决方案】需要把sdmap文件设置为内嵌资源
快速入门
A)使用sdmap的步骤。
step1)通过nuget安装依赖包:sdmap.ext.Dapper
通常只需安装sdmap.ext.Dapper,因为它将自动安装所有依赖项,包括sdmap和sdmap.ext。
step2) 在项目中的某个目录,创建一个空文本文件,并将其重命名为.sdmap
在项目属性窗口中,将文件“生成操作”从“无”设置为“嵌入资源”。
step3)初始化sdmap目录(该程序表示sdmap所在的程序集):
SetEmbeddedSqlAssembly(typeof(Program).Assembly);
注:
在执行任何数据库操作之前,必须先运行此代码。
此代码只需要在每个进程中执行一次。
初始化sdmap还有许多其他方法,您应该根据需要选择其中一种:
SetSqlDirectory-从磁盘上的物理文件夹初始化
SetSqlDirectoryAndWatch-从磁盘上的物理文件夹初始化,并在编辑这些文件夹sdmap文件时监视更改
SetEmbeddedSqlAssembly-从单个程序集初始化,sdmap自动解析以.sdmap结尾的所有资源文件
SetEmbeddedSqlAssemblys-从多个程序集初始化,sdmap自动解析以.sdmap结尾的所有资源文件
高级,您可以编写自己的ISDmapEmitter。
step4) 将一些SQL语句写入sdmap文件,最小sdmap文件可能如下所示:
sql GetUserById
{ SELECT * FROM [User] WHERE Id = @Id }注意:名称空间NS{…}不是必须的。
注: 如果要手动发出SQL语句,可能需要调用:
string finalSqlToExecute=DbConnectionExtensions.EmitSql(sqlMapId,parameterObject);
B)sdmap使用过程的关键类。
b1)ISdmapEmiter的实现.
using sdmap.Compiler; using sdmap.ext; using System.IO; using System.Linq; using System.Reflection; namespace ConfigLab.App.DbContexts { public class ConfigLabAppSqlEmiter : ISdmapEmiter { private SdmapCompiler _compiler = (SdmapCompiler)(object)new SdmapCompiler(); public string Emit(string statementId, object parameters) { return GetCommandText(statementId, parameters); } public void AddAssembly(Assembly assembly) { foreach (string item in from x in assembly.GetManifestResourceNames() where x.EndsWith(".sdmap") select x) { using (StreamReader streamReader = new StreamReader(assembly.GetManifestResourceStream(item))) { _compiler.AddSourceCode(streamReader.ReadToEnd()); } } } public static ConfigLabAppSqlEmiter CreateFrom(params Assembly[] assemblies) { ConfigLabAppSqlEmiter configLabAppSqlEmiter = new ConfigLabAppSqlEmiter(); foreach (Assembly assembly in assemblies) { configLabAppSqlEmiter.AddAssembly(assembly); } return configLabAppSqlEmiter; } private string GetCommandText(string statementId, object parameters) { return _compiler.Emit(statementId, parameters); } } }
b2)SdmapContext的实现.
using sdmap.ext; namespace ConfigLab.App.DbContexts { public class ConfigLabAppSdmapContext : SdmapContext { public ConfigLabAppSdmapContext(ISdmapEmiter maps) : this(maps) { } public ConfigLabAppSdmapContext() : this((ISdmapEmiter)(object)ConfigLabAppSqlEmiter.CreateFrom(typeof(UserResposibility).Assembly)) { } } }