Skip to content

ORM 实体基类

基础 ORM 实体定义库,提供不依赖任何第三方框架的实体基类和接口,支持审计追踪、软删除、乐观锁等企业级功能。

特性

  • 零框架依赖:仅使用 .NET 标准库,不依赖任何 ORM 框架,可自由搭配使用
  • 完整审计追踪:自动记录创建和更新信息(时间、用户ID、用户名)
  • 软删除支持:标记删除而非物理删除,支持数据恢复
  • 乐观锁并发控制:基于版本号的并发冲突检测机制
  • 多租户架构:内置租户ID支持,满足 SaaS 场景需求
  • 灵活继承体系:从基础接口到全功能基类的多层级选择

安装

bash
dotnet add package GameFrameX.Foundation.Orm.Entity

快速开始

csharp
using GameFrameX.Foundation.Orm.Entity;

// 继承 EntityBase 即可获得全部企业级功能
public class User : EntityBase
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string PasswordHash { get; set; }

    // EntityBase 自动提供的属性:
    // - long Id                    // 主键
    // - DateTime CreateTime        // 创建时间
    // - DateTime UpdateTime        // 更新时间
    // - long CreateUserId          // 创建人 ID
    // - long UpdateUserId          // 更新人 ID
    // - string CreateUserName      // 创建人姓名
    // - string UpdateUserName      // 更新人姓名
    // - bool IsDelete              // 软删除标记
    // - long Version               // 乐观锁版本
    // - bool IsEnabled             // 启用状态
}

var user = new User
{
    Username = "john_doe",
    Email = "john@example.com",
    PasswordHash = "hashed_password",
    CreateTime = DateTime.UtcNow,
    CreateUserId = 1,
    CreateUserName = "admin",
    IsEnabled = true
};

详细用法

核心接口

  • IEntity: 实体基础接口
  • IEntity<TKey>: 带主键的实体接口,支持泛型主键类型
  • IVersionedEntity: 版本控制实体接口,支持乐观锁

过滤器接口

  • ISafeCreatedFilter: 创建信息过滤器(CreatedIdCreatedTimeCreatedName
  • ISafeUpdateFilter: 更新信息过滤器(UpdateCountUpdateTimeUpdatedIdUpdatedName
  • ISafeDeletedFilter: 软删除过滤器(IsDeletedDeleteTimeDeletedIdDeletedName
  • ISafeEnabledFilter: 启用状态过滤器(IsEnabled
  • ITenantIdFilter: 租户ID过滤器(TenantId
  • ISelectFilter: 搜索查询过滤器(NameDescription
  • IOrganizationIdFilter: 机构ID过滤器(CreateOrganizationId

实体基类

EntityBaseId / EntityBaseId<TKey>

  • 提供主键字段
  • 支持 long 类型主键和泛型主键
  • 实现 IEntity 接口

EntityBase / EntityBase<TKey>

  • 继承自 EntityBaseId
  • 实现 ISafeCreatedFilterISafeUpdateFilterISafeDeletedFilterISafeEnabledFilterIVersionedEntity
  • 所有字段均为可空类型
  • 支持版本控制(乐观锁)

EntityTenantBase / EntityTenantBase<TKey>

  • 继承自 EntityBase
  • 实现 ITenantIdFilter
  • 支持多租户架构

EntitySelectBase

  • 继承自 EntityBase
  • 实现 ISelectFilter 接口
  • 包含名称和描述字段,适用于需要搜索的实体

核心组件

组件文件说明
EntityBaseEntityBase.cs全功能实体基类(ID、审计、软删除、版本控制)
EntityBaseId (Generic)EntityBaseId.cs自定义主键类型实体基类
IEntityIEntity.cs基础实体接口
IAuditableEntityIAuditableEntity.cs审计接口(创建/更新时间和用户)

自定义主键类型

csharp
// 使用 string 作为主键
public class Product : EntityBaseId<string>
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Description { get; set; }
}

// 使用 Guid 作为主键
public class Order : EntityBaseId<Guid>
{
    public string OrderNumber { get; set; }
    public decimal TotalAmount { get; set; }
    public DateTime OrderDate { get; set; }
}

var product = new Product
{
    Id = "PROD-001",
    Name = "Laptop",
    Price = 5999.99m,
    Description = "High performance laptop"
};

var order = new Order
{
    Id = Guid.NewGuid(),
    OrderNumber = "ORD-20240101-001",
    TotalAmount = 5999.99m,
    OrderDate = DateTime.UtcNow
};

接口实现

csharp
// 实现基础实体接口
public class Category : IEntity<int>
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

// 实现审计接口
public class AuditableCategory : IEntity<int>, IAuditableEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    // IAuditableEntity 接口属性
    public DateTime CreateTime { get; set; }
    public DateTime UpdateTime { get; set; }
    public long CreateUserId { get; set; }
    public long UpdateUserId { get; set; }
    public string CreateUserName { get; set; }
    public string UpdateUserName { get; set; }
}

多租户实体

csharp
public class TenantOrder : EntityTenantBase
{
    public string OrderNumber { get; set; }
    public decimal Amount { get; set; }
}

可搜索实体

csharp
public class SearchableCategory : EntitySelectBase
{
    public int? SortOrder { get; set; }
}

审计追踪

csharp
public class Document : EntityBase
{
    public string Title { get; set; }
    public string Content { get; set; }
}

var document = new Document
{
    Title = "Important Document",
    Content = "Document content...",
    CreateTime = DateTime.UtcNow,
    CreateUserId = currentUser.Id,
    CreateUserName = currentUser.Username,
    UpdateTime = DateTime.UtcNow,
    UpdateUserId = currentUser.Id,
    UpdateUserName = currentUser.Username
};

// 更新时自动维护审计信息
document.Content = "Updated content";
document.UpdateTime = DateTime.UtcNow;
document.UpdateUserId = currentUser.Id;
document.UpdateUserName = currentUser.Username;
document.Version++; // 乐观锁版本递增

软删除

csharp
// 软删除:标记为已删除而非物理删除
public void SoftDeleteUser(User user)
{
    user.IsDelete = true;
    user.UpdateTime = DateTime.UtcNow;
    user.UpdateUserId = currentUser.Id;
    user.UpdateUserName = currentUser.Username;
    dbContext.SaveChanges();
}

// 查询时过滤已删除记录
var activeUsers = dbContext.Users
    .Where(u => !u.IsDelete)
    .ToList();

// 恢复已删除记录
public void RestoreUser(User user)
{
    user.IsDelete = false;
    user.UpdateTime = DateTime.UtcNow;
    user.UpdateUserId = currentUser.Id;
    user.UpdateUserName = currentUser.Username;
    dbContext.SaveChanges();
}

乐观锁

csharp
public void UpdateUserWithOptimisticLock(long userId, string newEmail)
{
    var user = dbContext.Users.Find(userId);
    var originalVersion = user.Version;

    user.Email = newEmail;
    user.UpdateTime = DateTime.UtcNow;
    user.UpdateUserId = currentUser.Id;
    user.UpdateUserName = currentUser.Username;
    user.Version++;

    try
    {
        var rowsAffected = dbContext.Database.ExecuteSqlRaw(
            "UPDATE Users SET Email = {0}, Version = {1} WHERE Id = {2} AND Version = {3}",
            user.Email, user.Version, user.Id, originalVersion);

        if (rowsAffected == 0)
            throw new ConcurrencyException("Data modified by another user, please refresh and retry");
    }
    catch (DbUpdateConcurrencyException)
    {
        throw new ConcurrencyException("Concurrency conflict, please refresh and retry");
    }
}

启用/禁用状态管理

csharp
public class Feature : EntityBase
{
    public string Name { get; set; }
    public string Description { get; set; }
}

public void ToggleFeature(long featureId, bool enabled)
{
    var feature = dbContext.Features.Find(featureId);
    feature.IsEnabled = enabled;
    feature.UpdateTime = DateTime.UtcNow;
    feature.Version++;
    dbContext.SaveChanges();
}

var enabledFeatures = dbContext.Features
    .Where(f => f.IsEnabled && !f.IsDelete)
    .ToList();

最佳实践

  1. 按需选择基类:简单实体使用 EntityBaseId<TKey>,需要审计和软删除时使用 EntityBase,多租户场景使用 EntityTenantBase
  2. 设计原则遵循:每个接口和类都有明确的职责,通过继承和接口实现扩展功能,依赖抽象接口而非具体实现
  3. 可空类型灵活使用:所有字段均为可空类型,提供更好的灵活性,查询时注意空值判断
  4. 乐观锁必用场景:高并发更新场景务必使用版本控制,避免数据覆盖
  5. 软删除查询过滤:查询时始终过滤 IsDelete 标记,防止已删除数据泄露到业务层

API 参考

类/接口类型说明
IEntity接口实体基础接口
IEntity<TKey>接口带泛型主键的实体接口
IAuditableEntity接口审计接口(创建/更新时间和用户)
IVersionedEntity接口版本控制实体接口
ISafeCreatedFilter接口创建信息过滤器
ISafeUpdateFilter接口更新信息过滤器
ISafeDeletedFilter接口软删除过滤器
ISafeEnabledFilter接口启用状态过滤器
ITenantIdFilter接口租户ID过滤器
ISelectFilter接口搜索查询过滤器
IOrganizationIdFilter接口机构ID过滤器
EntityBaseId<TKey>基类自定义主键类型实体基类
EntityBase<TKey>基类全功能实体基类
EntityTenantBase<TKey>基类多租户实体基类
EntitySelectBase基类可搜索实体基类

许可证

MIT + Apache 2.0



快来请作者喝奶茶.我喝不惯咖啡





最后更新于: