视觉画布设计
canvas-design
基于设计原则创作静态视觉作品,用于海报与品牌图形。
sod【文档与办公】Use when needing a multi-paradigm .NET ORM with SQL-MAP (MyBatis-style XML mapping), OQL (Object Query Language), and traditional ORM. PDF.NET SOD: combines ORM + SQL-MAP + OQL for flexible .NET data access.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: sod description: "Use when needing a multi-paradigm .NET ORM with SQL-MAP (MyBatis-style XML mapping), OQL (Object Query Language), and traditional ORM. PDF.NET SOD: combines ORM + SQL-MAP + OQL for flexible .NET data access." tags:
项目地址: https://github.com/znlgis/SOD(社区主仓库见 https://gitee.com/znlgis/SOD)
官网: https://www.pwmis.com/sod/
官方文档: http://www.pwmis.com/sod/
NuGet:
PDF.NET.SODNuGet(.NET 6+):
PWMIS.SOD最新版本: PDF.NET.SOD 7.0.1 / PWMIS.SOD 6.0.3(截至2026-09,NuGet)
许可证: Apache-2.0
SOD 由 PDF.NET 演化而来,主要特点:
EntityBase,支持脏字段跟踪、字段映射、状态机dotnet add package PDF.NET.SOD
# 或对应数据库 Provider:
dotnet add package PDF.NET.SOD.MySQL
dotnet add package PDF.NET.SOD.PostgreSQL
<connectionStrings>
<add name="local" providerName="SqlServer"
connectionString="server=.;database=demo;uid=sa;pwd=..." />
</connectionStrings>
或代码:
using PWMIS.DataProvider.Data;
var db = MyDB.GetDBHelperByConnectionString(
"server=.;database=demo;uid=sa;pwd=...", "SqlServer");
using PWMIS.DataMap.Entity;
[Serializable]
public class User : EntityBase
{
public User() {
TableName = "Users";
IdentityName = "Id"; // 自增列
PrimaryKeys.Add("Id");
}
public int Id { get => getProperty<int>("Id");
set => setProperty("Id", value); }
public string Name { get => getProperty<string>("Name");
set => setProperty("Name", value, 50); }
public DateTime Time { get => getProperty<DateTime>("CreateTime");
set => setProperty("CreateTime", value); }
}
可通过 SOD CodeMaker 或 EntityBuilder 自动生成。
using PWMIS.DataMap.Entity;
var db = MyDB.GetDBHelperByConnectionName("local");
var q = new EntityQuery<User>(db);
var u = new User { Name = "Tom", Time = DateTime.Now };
q.Insert(u); // INSERT
u.Name = "Tom2";
q.Update(u); // UPDATE(仅脏字段)
var list = q.GetList(top: 10); // SELECT TOP 10
var u1 = q.GetEntity(new User { Id = 1 }); // by PK
q.Delete(u1); // DELETE
var u = new User();
var oql = OQL.From(u)
.Select(u.Id, u.Name)
.Where(cmp => cmp.Comparer(u.Id, ">", 10) &
cmp.Comparer(u.Name, "like", "%T%"))
.OrderBy(o => o.Asc(u.Id))
.END;
oql.Limit(20, 1); // 第 1 页,每页 20 条
var list = EntityQuery<User>.QueryList(oql, db);
聚合:
var sum = OQL.From(u).Select(u.Id.Sum()).END;
int total = (int)EntityQuery.ExecuteOql(sum, db);
var u = new User(); var o = new Order();
var oql = OQL.From(u)
.InnerJoin(o).On(u.Id, o.UserId)
.Select(u.Name, o.Amount)
.END;
Maps/UserMap.xml:
<sqlMap name="User">
<statement name="ListByName" desc="按姓名查">
<![CDATA[
select * from Users where Name like @Name
]]>
</statement>
</sqlMap>
var dal = new SqlMapper(db);
var rows = dal.ExecuteList<User>("User.ListByName",
new { Name = "%Tom%" });
通过 SOD 工具(SqlMapTool)从 XML 自动生成强类型 DAL 类。
var ds = db.ExecuteDataSet("select * from Users where Id=@Id",
CommandType.Text, db.GetParameter("@Id", 1));
int rows = db.ExecuteNonQuery("update Users set Name=@N where Id=@Id",
CommandType.Text,
db.GetParameter("@N", "Tom"),
db.GetParameter("@Id", 1));
db.BeginTransaction();
try {
q.Insert(u1);
q.Insert(u2);
db.Commit();
} catch {
db.Rollback();
throw;
}
或:
db.UseTransaction(() => {
q.Insert(u1); q.Insert(u2);
return true;
});
通过 MyDB.GetDBHelperByConnectionName(...) 选择不同连接配置;SOD 支持主从切换:
<add name="local-master" providerName="SqlServer" connectionString="..."/>
<add name="local-slave" providerName="SqlServer" connectionString="..."/>
写走 master,读走 slave;或借助 IReadDb / IWriteDb 接口。
仅替换 providerName:
| 数据库 | providerName |
|---|---|
| SQL Server | SqlServer |
| Oracle | Oracle |
| MySQL | MySql |
| PostgreSQL | PostgreSQL |
| SQLite | Sqlite |
| 达梦 | DaMeng |
| 人大金仓 | Kingbase |
| 神通 | OSCAR |
MyDB.SQL_LOG_INFO 输出慢 SQLdb.CommandTimeOutLimit(),不要 ToList 全量EntityBase,设置 TableName、IdentityName、PrimaryKeys,属性用 getProperty<T>() / setProperty()EntityQuery<T>;复杂条件 → OQL 链式 API;固定 SQL → SQL-MAP XMLproviderName(SqlServer / MySql / PostgreSQL / DaMeng 等)AdoHelper 实例内 BeginTransaction() → 操作 → Commit() / Rollback()getProperty<T>(name) / setProperty(name, value, size),不能用自动属性IdentityName 必须设置正确,否则 INSERT 后 Id 不更新Update() 只提交变更字段(调用 setProperty 的字段),性能优于全量更新oql.Limit(pageSize, pageIndex) 分页,不要 ToList 后手动分页| 场景 | 推荐方案 |
|---|---|
| 政企项目(达梦/金仓/神通) | SOD(多数据库支持最全) |
| 追求开发效率 | SqlSugar(链式查询更现代) |
| MyBatis 用户迁移 | SOD SQL-MAP 模式 |
| 新项目 | 评估 SqlSugar vs SOD 的数据库支持列表 |
| 问题 | 解决 |
|---|---|
| 字段映射错误 | 使用 MapField(...) 指定列名 |
| 自增主键未填回 | IdentityName 设置正确 |
| 中文乱码 | 数据库用 utf8mb4 / NVARCHAR |
| 事务跨连接失败 | 使用同一 AdoHelper 实例 |