04-实体类与ORM映射

news/2025/11/29 13:43:32/文章来源:https://www.cnblogs.com/znlgis/p/19286242

第四章:实体类与ORM映射

4.1 实体类基础

4.1.1 EntityBase类详解

EntityBase是SOD框架中所有实体类的基类,它提供了动态属性管理、元数据映射和状态追踪等核心功能。

public abstract class EntityBase
{// ===== 核心元数据属性 =====/// <summary>/// 映射的数据表名称/// </summary>public string TableName { get; set; }/// <summary>/// 自增/标识字段名称/// </summary>public string IdentityName { get; set; }/// <summary>/// 主键字段集合(支持联合主键)/// </summary>public List<string> PrimaryKeys { get; }/// <summary>/// 所有属性名称集合/// </summary>public string[] PropertyNames { get; }/// <summary>/// 所有属性值集合/// </summary>public object[] PropertyValues { get; }// ===== 核心方法 =====/// <summary>/// 获取属性值/// </summary>protected T getProperty<T>(string propertyName);/// <summary>/// 设置属性值/// </summary>protected void setProperty(string propertyName, object value, int length = 0);/// <summary>/// 索引器访问/// </summary>public object this[string propertyName] { get; set; }/// <summary>/// 设置外键关系/// </summary>protected void SetForeignKey<TParent>(string foreignKeyPropertyName);/// <summary>/// 获取表名(运行时)/// </summary>public string GetTableName();/// <summary>/// 判断属性是否被修改/// </summary>public bool PropertyChangedList(string propertyName);/// <summary>/// 重置属性修改状态/// </summary>public void ResetChanges();
}

4.1.2 实体类的生命周期

创建实体对象 → 设置属性值 → 状态追踪 → 持久化操作 → 状态重置│              │            │            │           │↓              ↓            ↓            ↓           ↓构造函数     setProperty    记录变更   生成SQL      ResetChanges初始化元数据   触发状态变更   字段列表   执行操作     清除变更状态

4.1.3 属性值存储机制

SOD实体类的属性值存储在内部的PropertyList集合中,而不是传统的私有字段:

// 传统实体类
public class TraditionalUser
{private string _name;  // 私有字段存储值public string Name{get { return _name; }set { _name = value; }}
}// SOD实体类
public class SODUser : EntityBase
{public string Name{// 值存储在EntityBase内部的PropertyList中get { return getProperty<string>("Name"); }set { setProperty("Name", value, 50); }}
}

这种设计的优势:

  • 自动追踪属性变化
  • 支持动态属性名映射
  • 便于序列化和反序列化
  • 支持索引器访问

4.2 元数据映射详解

4.2.1 表名映射

public class UserEntity : EntityBase
{public UserEntity(){// 基本映射TableName = "TbUser";// 带Schema的表名// TableName = "dbo.TbUser";// 动态表名(分表场景)// TableName = GetDynamicTableName();}private string GetDynamicTableName(){// 根据当前月份分表return $"TbUser_{DateTime.Now:yyyyMM}";}
}

4.2.2 主键映射

public class OrderEntity : EntityBase
{public OrderEntity(){TableName = "TbOrder";// 单一主键PrimaryKeys.Add("OrderId");// 联合主键// PrimaryKeys.Add("OrderId");// PrimaryKeys.Add("ProductId");}
}

4.2.3 标识字段(自增)映射

public class UserEntity : EntityBase
{public UserEntity(){TableName = "TbUser";// 设置自增字段IdentityName = "ID";PrimaryKeys.Add("ID");}public int ID{get { return getProperty<int>("ID"); }set { setProperty("ID", value); }}
}// 使用时,插入后自动回填ID
var user = new UserEntity { Name = "张三" };
EntityQuery<UserEntity>.Instance.Insert(user, db);
Console.WriteLine($"新用户ID: {user.ID}");  // 自动获得自增值

4.2.4 字段名映射

public class UserEntity : EntityBase
{public UserEntity(){TableName = "TbUser";}// 属性名与字段名相同public string Name{get { return getProperty<string>("Name"); }set { setProperty("Name", value, 50); }}// 属性名与字段名不同public string DisplayName{get { return getProperty<string>("UserDisplayName"); }  // 映射到UserDisplayName字段set { setProperty("UserDisplayName", value, 100); }}
}

4.2.5 字段长度映射

public class UserEntity : EntityBase
{// 指定字段长度,用于Code First建表public string Name{get { return getProperty<string>("Name"); }set { setProperty("Name", value, 50); }  // 长度50}public string Remark{get { return getProperty<string>("Remark"); }set { setProperty("Remark", value, 500); }  // 长度500}// 不指定长度,使用默认值public string Description{get { return getProperty<string>("Description"); }set { setProperty("Description", value); }  // 默认长度}
}

4.2.6 外键映射

// 主表
public class OrderEntity : EntityBase
{public OrderEntity(){TableName = "TbOrder";IdentityName = "OrderId";PrimaryKeys.Add("OrderId");}public long OrderId { get { ... } set { ... } }public string OrderNo { get { ... } set { ... } }// 子实体列表public List<OrderItemEntity> Items { get; set; }
}// 子表
public class OrderItemEntity : EntityBase
{public OrderItemEntity(){TableName = "TbOrderItem";IdentityName = "ItemId";PrimaryKeys.Add("ItemId");// 设置外键关系SetForeignKey<OrderEntity>("OrderId");}public long ItemId { get { ... } set { ... } }public long OrderId { get { ... } set { ... } }  // 外键字段public string ProductName { get { ... } set { ... } }
}

4.3 数据类型映射

4.3.1 基本类型映射

C#类型 SQL Server MySQL Oracle 说明
int int int NUMBER(10) 整数
long bigint bigint NUMBER(19) 长整数
float real float FLOAT 单精度浮点
double float double FLOAT 双精度浮点
decimal decimal decimal NUMBER 精确数值
string nvarchar varchar VARCHAR2 字符串
bool bit tinyint(1) NUMBER(1) 布尔值
DateTime datetime datetime DATE 日期时间
Guid uniqueidentifier char(36) RAW(16) GUID
byte[] varbinary blob BLOB 二进制

4.3.2 可空类型处理

public class UserEntity : EntityBase
{// 可空整数public int? Age{get { return getProperty<int?>("Age"); }set { setProperty("Age", value); }}// 可空日期public DateTime? Birthday{get { return getProperty<DateTime?>("Birthday"); }set { setProperty("Birthday", value); }}// 可空布尔public bool? IsVip{get { return getProperty<bool?>("IsVip"); }set { setProperty("IsVip", value); }}
}// 使用时
var user = new UserEntity();
user.Age = null;  // 允许设置null
user.Birthday = null;

4.3.3 枚举类型处理

// 定义枚举
public enum UserStatus
{Inactive = 0,Active = 1,Locked = 2
}public class UserEntity : EntityBase
{// 方式1:存储为整数public int StatusValue{get { return getProperty<int>("Status"); }set { setProperty("Status", value); }}// 包装为枚举(不参与映射)[System.ComponentModel.DataAnnotations.Schema.NotMapped]public UserStatus Status{get { return (UserStatus)StatusValue; }set { StatusValue = (int)value; }}// 方式2:直接使用枚举public UserStatus StatusEnum{get { return getProperty<UserStatus>("Status"); }set { setProperty("Status", (int)value); }}
}

4.4 高级映射技术

4.4.1 动态表名(分表)

public class UserLogEntity : EntityBase
{private string _tableMonth;public UserLogEntity() : this(DateTime.Now) { }public UserLogEntity(DateTime logDate){_tableMonth = logDate.ToString("yyyyMM");TableName = $"TbUserLog_{_tableMonth}";IdentityName = "LogId";PrimaryKeys.Add("LogId");}public long LogId { get { ... } set { ... } }public int UserId { get { ... } set { ... } }public string Action { get { ... } set { ... } }public DateTime LogTime { get { ... } set { ... } }
}// 使用
// 查询2024年1月的日志
var janLog = new UserLogEntity(new DateTime(2024, 1, 15));
var oql = OQL.From(janLog).Select().END;
var logs = EntityQuery<UserLogEntity>.QueryList(oql);
// 实际查询: SELECT * FROM TbUserLog_202401// 查询2024年2月的日志
var febLog = new UserLogEntity(new DateTime(2024, 2, 15));
var oql2 = OQL.From(febLog).Select().END;
// 实际查询: SELECT * FROM TbUserLog_202402

4.4.2 动态主键

public class UserEntity : EntityBase
{public UserEntity(){TableName = "TbUser";IdentityName = "ID";PrimaryKeys.Add("ID");  // 默认主键}public int ID { get { ... } set { ... } }public string LoginName { get { ... } set { ... } }public string Email { get { ... } set { ... } }
}// 使用场景:根据登录名删除用户
var user = new UserEntity();
user.PrimaryKeys.Clear();
user.PrimaryKeys.Add("LoginName");  // 临时更换主键
user.LoginName = "zhangsan";EntityQuery<UserEntity>.Instance.Delete(user, db);
// 生成: DELETE FROM TbUser WHERE LoginName = @LoginName

4.4.3 虚拟映射(不存在的字段)

public class UserEntity : EntityBase
{public UserEntity(){TableName = "TbUser";IdentityName = "ID";PrimaryKeys.Add("ID");}public int ID { get { ... } set { ... } }public string FirstName { get { ... } set { ... } }public string LastName { get { ... } set { ... } }// 虚拟属性:不映射到数据库字段// 通过在属性上不使用getProperty/setProperty实现public string FullName{get { return $"{FirstName} {LastName}"; }}// 或者使用普通属性(不参与数据库操作)private int _tempData;public int TempData{get { return _tempData; }set { _tempData = value; }}
}

4.4.4 计算字段

public class OrderEntity : EntityBase
{public decimal UnitPrice { get { ... } set { ... } }public int Quantity { get { ... } set { ... } }public decimal Discount { get { ... } set { ... } }// 计算字段:总价public decimal TotalPrice{get { return UnitPrice * Quantity * (1 - Discount); }}
}

4.5 实体类工厂

4.5.1 EntityBuilder动态创建

使用接口动态创建实体类,无需定义完整的实体类:

// 定义接口
public interface IUser
{int ID { get; set; }string Name { get; set; }string Email { get; set; }
}// 动态创建实体对象
IUser user = EntityBuilder.CreateEntity<IUser>();
user.Name = "张三";
user.Email = "zhangsan@example.com";// 查询
var oql = OQL.FromObject<IUser>().Select().Where((cmp, u) => cmp.Property(u.Name) == "张三").END;var users = oql.ToList();

4.5.2 接口命名约定

// 接口类型 IXxx 默认映射到表 Xxx(去掉前缀I)
public interface IUser { }       // → 表名: User
public interface ITbUser { }     // → 表名: TbUser
public interface IDbUser { }     // → 表名: DbUser// 可以通过GOQL指定表名
var oql = OQL.FromObject<IUser>("CustomTableName").Select().END;

4.5.3 动态实体与静态实体的选择

特性 动态实体(接口) 静态实体(类)
定义方式 接口 继承EntityBase的类
元数据配置 使用约定 在构造函数中配置
自增字段 不支持 支持
外键关系 不支持 支持
自定义方法 不支持 支持
适用场景 简单查询 完整CRUD

4.6 实体类设计最佳实践

4.6.1 规范的实体类定义

using PWMIS.DataMap.Entity;
using System;namespace MyProject.Entities
{/// <summary>/// 用户实体类/// 映射表:TbUser/// </summary>public class UserEntity : EntityBase{#region 构造函数public UserEntity(){TableName = "TbUser";IdentityName = "ID";PrimaryKeys.Add("ID");}#endregion#region 主键/标识字段/// <summary>/// 用户ID(主键,自增)/// </summary>public int ID{get { return getProperty<int>(nameof(ID)); }set { setProperty(nameof(ID), value); }}#endregion#region 业务字段/// <summary>/// 用户名/// </summary>public string Name{get { return getProperty<string>(nameof(Name)); }set { setProperty(nameof(Name), value, 50); }}/// <summary>/// 邮箱/// </summary>public string Email{get { return getProperty<string>(nameof(Email)); }set { setProperty(nameof(Email), value, 100); }}/// <summary>/// 状态:0-禁用,1-启用/// </summary>public int Status{get { return getProperty<int>(nameof(Status)); }set { setProperty(nameof(Status), value); }}/// <summary>/// 创建时间/// </summary>public DateTime CreateTime{get { return getProperty<DateTime>(nameof(CreateTime)); }set { setProperty(nameof(CreateTime), value); }}/// <summary>/// 最后登录时间(可空)/// </summary>public DateTime? LastLoginTime{get { return getProperty<DateTime?>(nameof(LastLoginTime)); }set { setProperty(nameof(LastLoginTime), value); }}#endregion#region 关联实体/// <summary>/// 用户角色列表/// </summary>public List<UserRoleEntity> Roles { get; set; }#endregion#region 计算属性/// <summary>/// 是否已激活/// </summary>public bool IsActive => Status == 1;#endregion}
}

4.6.2 使用nameof提高可维护性

// 推荐:使用nameof
public string Name
{get { return getProperty<string>(nameof(Name)); }set { setProperty(nameof(Name), value, 50); }
}// 不推荐:使用字符串字面量
public string Name
{get { return getProperty<string>("Name"); }set { setProperty("Name", value, 50); }
}

4.6.3 分离业务接口

// 定义业务接口
public interface IUser
{int ID { get; set; }string Name { get; set; }string Email { get; set; }
}// 实体类实现接口
public class UserEntity : EntityBase, IUser
{public UserEntity(){TableName = "TbUser";IdentityName = "ID";PrimaryKeys.Add("ID");}public int ID { get { ... } set { ... } }public string Name { get { ... } set { ... } }public string Email { get { ... } set { ... } }
}// 业务层使用接口
public class UserService
{public IUser GetUser(int id){// 返回接口类型,隐藏实现细节return EntityQuery<UserEntity>.QueryObject(...);}
}

4.6.4 实体类继承

// 基础实体类(包含通用字段)
public abstract class BaseEntity : EntityBase
{public DateTime CreateTime{get { return getProperty<DateTime>(nameof(CreateTime)); }set { setProperty(nameof(CreateTime), value); }}public DateTime? UpdateTime{get { return getProperty<DateTime?>(nameof(UpdateTime)); }set { setProperty(nameof(UpdateTime), value); }}public int CreatorId{get { return getProperty<int>(nameof(CreatorId)); }set { setProperty(nameof(CreatorId), value); }}
}// 业务实体类
public class UserEntity : BaseEntity
{public UserEntity(){TableName = "TbUser";IdentityName = "ID";PrimaryKeys.Add("ID");}public int ID { get { ... } set { ... } }public string Name { get { ... } set { ... } }// 自动继承了CreateTime, UpdateTime, CreatorId
}

4.7 本章小结

本章详细介绍了SOD框架的实体类与ORM映射机制:

  1. EntityBase基类:核心方法和属性的使用
  2. 元数据映射:表名、主键、标识字段、字段名、外键的映射
  3. 数据类型映射:基本类型、可空类型、枚举类型的处理
  4. 高级映射技术:分表、动态主键、虚拟映射
  5. 实体类工厂:EntityBuilder动态创建实体
  6. 最佳实践:规范的实体类定义方式

掌握实体类的定义和映射是使用SOD框架进行ORM开发的基础,在下一章我们将学习强大的OQL查询语言。


下一章预告:第五章将深入讲解OQL查询语言,包括基础查询、条件表达式、关联查询、分页等高级特性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/980774.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI元人文:论数字猴戏与缺失的“破茧之悟”

AI元人文:论数字猴戏与缺失的“破茧之悟” 在方寸屏幕之间,一场亘古的“猴戏”正在全新上演。 数字班主取代了古道艺人,虚拟锣鼓替换了乡野铜钹,流量与点赞成了新的喝彩。这场戏码,从乡土戏台迁至算法剧场,围观与…

02-框架架构与核心组件

第二章:框架架构与核心组件 2.1 整体架构设计 2.1.1 分层架构 SOD框架采用经典的分层架构设计,从底层到顶层依次为: ┌────────────────────────────────────────────…

03-快速入门与环境配置

第三章:快速入门与环境配置 3.1 开发环境准备 3.1.1 必要的开发工具工具 要求 说明Visual Studio 2019/2022 推荐使用最新版本.NET SDK 2.0 - 8.0 根据项目目标框架选择NuGet 内置 包管理工具SQL Server / MySQL / 其…

01-框架概述与设计理念

第一章:SOD框架概述与设计理念 1.1 SOD框架简介 1.1.1 什么是SOD框架 SOD框架(SQL-MAP、ORM、Data Controls)是一个拥有超过15年历史的国产开源企业级数据应用开发框架。它诞生于2006年,最初名为PDF.NET框架,后来…

小红书代运营公司TOP5权威推荐:资质齐全品牌甄选,助力企业

当下,小红书以2.6亿月活用户、70%以上的年轻消费群体成为企业精准获客的核心阵地。2024年数据显示,小红书企业号数量同比增长65%,但超30%的企业因代运营选择不当遭遇流量陷阱:内容同质化导致笔记零曝光、投流ROI不…

电力电缆厂家TOP5权威推荐:甄选质量过硬、客户反馈佳的供应

电缆作为能源传输与工业运行的血管,其品质直接决定项目安全与长期价值。2024年数据显示,我国电缆市场规模超1.2万亿元,但58%的工程安全事故与劣质电缆相关,30%的采购方因选型不当导致返工损失。面对非标泛滥、适配…

CF1666C-Connect the Points

CF1666C-Connect the Points 题目大意 给你平面上的三个点,用垂直于坐标轴的线段连接这三个点,使得线段总长度最小。 题解 考虑 \(x\) 坐标中间的那个点,建立一条覆盖三个点纵坐标的竖直的线段。将两侧的两个点通过…

打磨细节质感,成就卓越代码——《代码大全2》第六部分读后感

打磨细节质感,成就卓越代码——《代码大全2》第六部分读后感 《代码大全2》第六部分“代码构建中的细节”聚焦编程实践的微观层面,从变量命名、注释风格、代码格式到控制结构优化、异常处理规范等细节入手,系统阐述…

哈尔滨精密轴承代理商综合实力TOP10排行榜

为了让榜单经得起推敲,我们联合黑龙江省机械工程学会,参照国际轴承协会(FAGMA)2025 年最新标准,花了两个月做实地调研。所有数据均经第三方机构 “中机检测” 验证,全程拒绝企业自报数据,这也是为啥能成为多家国…

2025年工业冷风机节能效率排行榜出炉,炼胶车间通风降温/制造业车间通风降温/机械厂车间降温/炼钢车间通风降温工业冷风机厂商选哪家

行业格局深度解析 随着制造业绿色转型加速,工业冷风机作为车间降温的关键设备,其节能效率成为企业采购的核心考量因素。据最新市场调研数据显示,2024年工业冷风机市场规模已达127亿元,同比增长18.3%。本文基于公开…

2025 年 11 月空调机组厂家最新推荐,实力品牌深度解析采购无忧之选!

2025 年全球商用空调机组市场需求持续攀升,规模预计突破 920 亿美元,同比增长 8.5%,但行业数据显示,42% 的采购方因品牌选择失误导致后期维护成本增加 30% 以上。为破解采购困境,本次推荐联合国际空气处理与制冷协…

3. vim上手 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

深耕代码质量,筑牢工程根基——《代码大全2》第四部分读后感

深耕代码质量,筑牢工程根基——《代码大全2》第四部分读后感 《代码大全2》第四部分“全面质量管理”以“构建高质量代码”为核心,从软件质量的本质、缺陷预防、测试策略到持续改进,系统拆解了代码从“可用”到“优…

2025年哈尔滨精密轴承厂家综合实力前十强排行榜

轴承的 “灵魂” 是精度,我们以 P 级精度(P2/P4/P5)量产能力为核心指标,参考数字化车间建设水平。像新哈精密轴承有黑龙江省数字化示范车间,哈轴集团能实现 P4 级轴承工业化量产,这类企业直接加分。一、选轴承像…

2025年空调机组厂家最新推荐,产能、专利、环保三维数据透视!

2025 年全球空调机组市场规模持续扩容,据行业测算同比增长 7.5%,但产品性能参差、适配性不足等问题仍困扰采购决策。本次推荐基于国际权威测评标准编制,测评流程严格遵循 ANSI/ASHRAE Standard 16-2016 检测规范,对…

2025年空调机组厂家最新推荐,组合式,直膨式净化,变风量,远程射流,转轮热回收空调机组公司测评

2025 冷年全球空调总出货规模达 2.21 亿台,同比增长 12.9%,但市场中 TOP6-8 长尾品牌均价下滑 22% 仍难提升份额,产品性能与可靠性差异显著。为破解采购决策难题,本次推荐依托国际权威测评体系编制,测评流程严格遵…

2025年度工部优选十大品牌排名:工部优选的十个领先品牌是什

工程行业的品牌选择向来是甲方、施工单位与设计院的核心痛点——虚假榜单充斥市场、低价内卷扰乱判断、跨平台调研消耗大量时间。作为工程行业生态服务平台的标杆,工部优选依托业主、设计院、总包的真实采购数据,发布…

2025年十大诚信且资质齐全的宅基地建房企业推荐,专业乡墅设

在乡村振兴的浪潮下,越来越多的人选择返乡建房,一栋安全可靠、设计合理的宅基地自建房,成为承载乡愁与家庭幸福的重要载体。然而,乡村建房市场鱼龙混杂,如何找到诚信可靠、资质齐全的宅基地建房企业,成为许多人的…

如何被更新的?就是[人工智能-大模型-122]:模型层 - RNN是通过神经元还是通过张量时间记录状态信息?时间状态信息

如何被更新的?就是[人工智能-大模型-122]:模型层 - RNN是通过神经元还是通过张量时间记录状态信息?时间状态信息pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; …

深入解析:SSH 密钥从 RSA 到 Ed25519

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …