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

使用ConcurrentDictionary时仍触发Conn构造函数的问题咨询

问题:避免EF Core查询时触发Conn对象的自定义构造函数

这是之前一个问题的后续提问,我现在用ConcurrentDictionary存储Conn实例,但执行查询时还是会触发Conn的构造函数,这是我想避免的——我只想获取已存在的Conn实例,不想重新创建。

原代码

public static ConcurrentDictionary<string, Conn> GetAllToDictionary(DbContext context)
{
    var result = new ConcurrentDictionary<string, Conn>();
    foreach (var conn in context.Set<Conn>().ToList())
        result.TryAdd(conn.Name, conn);
    return result;
}

显然执行context.Set<Conn>().ToList()时会调用Conn的构造函数,怎么避免?

补充:Conn构造函数

public Conn(string name, IPAddress address, int port)
{
    Name = name;
    Address = address;
    Port = port;
    TcpConnection = new TcpConnection(Address, Port, 8192);
    Status = ConnectionStatus.NotConnected;
}

解决思路与方案

EF Core从数据库查询实体时,必然会创建实体实例——不管用无参还是自定义有参构造,这是它的核心工作机制。你要避免的本质是重复初始化构造函数里的资源(比如TcpConnection),或者复用内存中已有的Conn实例,可以按以下方式处理:

1. 维护全局实例缓存,复用已有对象

先把已创建的Conn实例存在全局缓存中,查询数据库时只取字段数据,匹配缓存实例而非让EF新建:

// 全局缓存,可放在Conn类或独立缓存类中
private static readonly ConcurrentDictionary<string, Conn> _connCache = new ConcurrentDictionary<string, Conn>();

public static ConcurrentDictionary<string, Conn> GetAllToDictionary(DbContext context)
{
    // 仅查询数据库中的核心字段,避免EF实例化完整Conn对象
    var dbConnData = context.Set<Conn>()
        .Select(c => new { c.Name, c.Address, c.Port })
        .ToList();

    foreach (var data in dbConnData)
    {
        // 缓存中不存在才创建实例,后续查询直接复用缓存
        _connCache.TryAdd(data.Name, new Conn(data.Name, data.Address, data.Port));
    }

    return new ConcurrentDictionary<string, Conn>(_connCache);
}

2. 分离数据初始化与资源初始化

把构造函数里的TcpConnection等资源初始化逻辑延迟到首次使用时,避免EF每次创建实例都初始化资源:

// 给EF使用的私有无参构造(EF可能需要,视配置而定)
private Conn() { }

public Conn(string name, IPAddress address, int port)
{
    Name = name;
    Address = address;
    Port = port;
    Status = ConnectionStatus.NotConnected;
    // 移除构造内的TcpConnection初始化
}

// 延迟初始化资源的方法
public void InitializeTcpConnection()
{
    if (TcpConnection == null)
    {
        TcpConnection = new TcpConnection(Address, Port, 8192);
    }
}

后续使用Conn时,仅在需要连接的场景调用InitializeTcpConnection即可。

3. 利用EF上下文的一级缓存(有限场景)

如果你的DbContext是复用的(比如长生命周期上下文),EF的一级缓存会自动复用相同主键的实例,但该方案仅适用于同一上下文内的重复查询,跨上下文场景仍需依赖全局缓存。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 02:01:03