You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用数据库实体与业务逻辑实体时,如何避免重复定义属性?

解决方案

针对实体类与业务类属性重复的问题,提供三种可行方案,你可以根据项目架构需求选择:

方案1:业务类继承实体类

让RoomBL直接继承Room实体,复用所有数据属性,仅添加业务专属的属性与方法:

public class RoomBL : Room
{
    public IRoomUserRepository UserRepository { get; }
    public RoomExtraData ExtraData { get; }

    public RoomBL(Room room, IRoomUserRepository userRepository, RoomExtraData extraData)
    {
        // 复制基类实体属性
        Id = room.Id;
        Name = room.Name;
        Layout = room.Layout;
        OwnerId = room.OwnerId;
        MaxUsersAllowed = room.MaxUsersAllowed;
        Description = room.Description;
        IsMuted = room.IsMuted;
        Settings = room.Settings;
        PaintSettings = room.PaintSettings;
        PlayerRights = room.PlayerRights;
        Tags = room.Tags;
        Likes = room.Likes;
        FurnitureItems = room.FurnitureItems;
        // 初始化业务专属内存状态
        ChatMessages = [];

        UserRepository = userRepository;
        ExtraData = extraData;
    }

    public async Task RunPeriodicCheckAsync()
    {
        var users = UserRepository.GetAll();
        
        foreach (var roomUser in users)
        {
            await roomUser.RunPeriodicCheckAsync();
        }

        var statusWriter = new RoomUserStatusWriter(users).GetAllBytes();
        var dataWriter = new RoomUserDataWriter(users).GetAllBytes();

        await UserRepository.BroadcastDataAsync(statusWriter);
        await UserRepository.BroadcastDataAsync(dataWriter);
    }

    public async ValueTask DisposeAsync()
    {
        await UserRepository.DisposeAsync();
    }
}

优点:完全消除属性重复,代码简洁;业务类可直接使用实体的所有属性。
缺点:实体与业务类耦合度高,实体结构变更时业务类需同步调整;实体上的数据库特性会被业务类继承,不符合单一职责。

方案2:实体类添加非持久化属性

在Room实体中用[NotMapped]标记不需要存入数据库的属性,同时将业务方法整合到实体类中:

public class Room
{
    public int Id { get; set; }
    public string Name { get; set; }
    public RoomLayout Layout { get; }
    public int OwnerId { get; set; }
    public int MaxUsersAllowed { get; set; }
    public string Description { get; set; }
    public bool IsMuted { get; set; }
    public RoomSettings Settings { get; set; }
    public RoomPaintSettings PaintSettings { get; set; }
    public List<RoomPlayerRight> PlayerRights { get; set; }
    public List<RoomChatMessage> ChatMessages { get; set; } = [];
    public List<RoomTag> Tags { get; set; }
    public List<PlayerRoomLike> Likes { get; set; }
    public List<RoomFurnitureItem> FurnitureItems { get; set; }

    // 非持久化属性,标记NotMapped避免数据库映射
    [NotMapped]
    public IRoomUserRepository UserRepository { get; set; }
    [NotMapped]
    public RoomExtraData ExtraData { get; set; }

    public async Task RunPeriodicCheckAsync()
    {
        var users = UserRepository.GetAll();
        
        foreach (var roomUser in users)
        {
            await roomUser.RunPeriodicCheckAsync();
        }

        var statusWriter = new RoomUserStatusWriter(users).GetAllBytes();
        var dataWriter = new RoomUserDataWriter(users).GetAllBytes();

        await UserRepository.BroadcastDataAsync(statusWriter);
        await UserRepository.BroadcastDataAsync(dataWriter);
    }

    public async ValueTask DisposeAsync()
    {
        await UserRepository.DisposeAsync();
    }
}

优点:无需额外业务类,所有逻辑集中在一个类,调用便捷。
缺点:违反单一职责原则,实体类同时承担数据持久化与业务逻辑职责,后期代码会臃肿难维护;依赖注入放到实体类中,会增加实体创建的复杂度。

方案3:组合模式(推荐)

让RoomBL持有Room实体的实例,通过包装属性复用数据,彻底分离业务逻辑与数据模型:

public class RoomBL
{
    private readonly Room _room;
    public IRoomUserRepository UserRepository { get; }
    public RoomExtraData ExtraData { get; }
    public List<RoomChatMessage> ChatMessages { get; } = [];

    public RoomBL(Room room, IRoomUserRepository userRepository, RoomExtraData extraData)
    {
        _room = room;
        UserRepository = userRepository;
        ExtraData = extraData;
    }

    // 包装实体属性,对外暴露
    public int Id => _room.Id;
    public string Name
    {
        get => _room.Name;
        set => _room.Name = value;
    }
    public RoomLayout Layout => _room.Layout;
    public int OwnerId => _room.OwnerId;
    public int MaxUsersAllowed
    {
        get => _room.MaxUsersAllowed;
        set => _room.MaxUsersAllowed = value;
    }
    public string Description
    {
        get => _room.Description;
        set => _room.Description = value;
    }
    public bool IsMuted => _room.IsMuted;
    public RoomSettings Settings => _room.Settings;
    public RoomPaintSettings PaintSettings => _room.PaintSettings;
    public List<RoomPlayerRight> PlayerRights => _room.PlayerRights;
    public List<RoomTag> Tags => _room.Tags;
    public List<PlayerRoomLike> Likes => _room.Likes;
    public List<RoomFurnitureItem> FurnitureItems => _room.FurnitureItems;

    public async Task RunPeriodicCheckAsync()
    {
        var users = UserRepository.GetAll();
        
        foreach (var roomUser in users)
        {
            await roomUser.RunPeriodicCheckAsync();
        }

        var statusWriter = new RoomUserStatusWriter(users).GetAllBytes();
        var dataWriter = new RoomUserDataWriter(users).GetAllBytes();

        await UserRepository.BroadcastDataAsync(statusWriter);
        await UserRepository.BroadcastDataAsync(dataWriter);
    }

    public async ValueTask DisposeAsync()
    {
        await UserRepository.DisposeAsync();
    }
}

优点:严格遵循单一职责,Room仅负责数据持久化,RoomBL仅负责业务逻辑;两者耦合度低,修改其中一个不会影响另一个;依赖注入逻辑更清晰。
缺点:需要手动包装实体属性,初期代码量稍大,可通过代码生成工具(如T4模板、Roslyn源码生成)自动生成包装代码,减少重复劳动。


内容的提问来源于stack exchange,提问作者user5405648

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:58:30