博客 (191)

目标: 在运行 HarmonyOS Next 的华为 MateBook Pro 上侧载安装第三方应用程序。

所需准备

  1. 一台运行 HarmonyOS Next 的华为 MateBook Pro

  2. 一台 Windows 电脑

  3. 一根数据线

    • USB-A to Type-C

    • 或 Type-C to Type-C (确保能将两台电脑连接)。

  4. 网络连接:两台电脑需在同一局域网下(用于无线调试连接)。

步骤详解

第一步:鸿蒙 PC (MateBook Pro) 端设置 (启用开发者模式与调试)

  1. 连接设备: 使用数据线将鸿蒙 MateBook Pro 连接到 Windows 电脑。

  2. 打开设置: 在鸿蒙 PC 上,进入 设置

  3. 进入关于本机: 在设置中,找到并点击 关于本机 或您的 电脑型号

  4. 启用开发者模式

    • 在“关于本机”界面,找到 软件版本 或 HarmonyOS 版本

    • 连续点击 软件版本/HarmonyOS 版本 文字 5 次以上

    • 系统会提示“您已处于开发者模式”或提示重启进入开发者模式。按提示重启电脑(如果需要)。

  5. 打开开发者选项

    • 重启后,回到 设置 -> 系统 -> 开发者选项 (路径可能略有不同,在“系统和更新”或“隐私与安全”下查找)。

  6. 启用 USB 调试

    • 在开发者选项中,找到 USB 调试,将其开启

    • 首次开启时,可能会弹出提示(连接线后或稍后操作时),点击 允许

    • 注意提示:系统可能提示“Matebook Pro 上的右上角的 Type-C 口可以进行调试”,确保使用正确的接口连接调试线。如果弹出“始终允许本机调试”选项,勾选并允许

  7. 启用并记录无线调试信息

    • 在开发者选项中,找到 无线调试,将其开启

    • 开启后,系统会显示一个 IP 地址和端口号(例如 192.168.x.x:xxxxx)。务必准确记下这个 IP 地址和端口号,后续在 Windows 端连接时必须用到。

    • 至此,鸿蒙 PC 端的准备工作完成。

第二步:Windows 电脑端操作 (使用小白调试助手)

  1. 获取工具和 HAP 包

    • 访问包含 HarmonyOS Next 可用 HAP 包的资源(如 GitHub 上的相关仓库,搜索 “HarmonyOS Next HAP”)。

    • 下载小白调试助手

      • 在工具仓库中找到 小白调试助手 或类似名称。

      • 点击 Latest (最新版本)。

      • 点击 Download 下载其 Windows 版压缩包(.zip 文件)。

    • 下载目标应用的 HAP 包(以 ClashBox 为例,你也可以使用自己已有的 .hap 文件):

      • 在应用仓库中找到 ClashBox

      • 同样点击 Latest -> Download 下载其 HAP 包(.hap 文件)。

  2. 准备小白调试助手

    • 将下载的小白调试助手压缩包解压到一个非中文且无空格路径的文件夹。

    • 进入解压后的文件夹,找到可执行文件。双击运行。根据 Windows SmartScreen 或安全软件提示(若有),选择 更多信息 -> 仍要运行

  3. 登录华为开发者账号 (强烈推荐)

    • 在小白调试助手界面,找到登录入口(通常在界面顶部或设置中),点击 登录

    • 使用您的华为开发者账号登录(登录时,您的华为手机可能会收到验证码,或在鸿蒙PC上验证)。

    • 输入验证码,并在授权请求页面点击 允许。登录成功后,界面通常会显示您的账号昵称或ID。

    • 重要: 开发者账号签发的应用证书有效期通常为 6 个月普通账号14 天。为方便使用,建议申请华为开发者账号。

  4. 连接鸿蒙设备

    • 在小白调试助手主界面,找到 连接设备添加设备 或类似功能的按钮并点击。

    • 在弹出的连接窗口(通常是输入IP和端口的对话框)中:

      • 输入您在鸿蒙 PC 上 无线调试 功能中记录的 IP 地址

      • 输入记录的 端口号

    • 点击 确定连接 或 OK

    • 连接成功:如果地址和端口输入正确,且鸿蒙 PC 的开发者选项已开启无线调试:

      • 鸿蒙 PC 可能弹出调试请求(“允许调试?”),勾选“始终允许”并点击 允许

      • 小白调试助手界面会显示“连接成功”或目标设备信息。

      • (若未弹出提示框但连接成功,也属正常)

第三步:安装第三方 HAP 包

  1. 选择 HAP 包

    • 确保设备已连接成功。

    • 在小白调试助手界面,找到 选择 HAP加载 HAP安装应用 或类似按钮(通常在文件菜单或主功能区)。

    • 点击该按钮,浏览文件系统,找到您下载好的目标 HAP 文件(如 ClashBox-xxx.hap),选中并点击 打开

  2. 开始安装

    • 选择好 HAP 文件后,小白调试助手界面通常会激活 开始调试安装 或 运行 按钮。

    • 点击 开始调试 或 安装

  3. 等待安装完成

    • 小白调试助手会开始处理 HAP 包:进行签名、推送到设备并安装。

    • 观察进度条或日志输出,耐心等待直至提示“安装成功”

第四步:在鸿蒙 PC 上使用安装的应用

  • 安装完成后,返回您的鸿蒙 MateBook Pro。

  • 在桌面或 开始菜单 中,查找您刚刚安装的应用图标(如 ClashBox)。

  • 点击图标即可启动使用该应用。

常见问题处理

  • 签名错误/证书问题:在小白调试助手内寻找 **清理缓存重置证书重新登录** 或类似选项。执行后,重新登录开发者账号,再尝试安装。确保登录的是开发者账号。

  • Java 环境报错:如果小白调试助手提示需要 Java 环境(如 java 命令未找到),按照其提示点击安装,它会引导下载并安装所需的 Java Runtime Environment (JRE)。

  • 连接失败

    • 检查鸿蒙 PC 的 无线调试 IP 和端口号是否变化(息屏、重启、网络切换可能导致变化),在开发者选项里重新确认并输入。

    • 确保两台电脑在同一局域网

    • 检查鸿蒙 PC 的 **USB 调试 和 无线调试 是否已开启**。

    • 尝试在鸿蒙 PC 的开发者选项中关闭再重新开启 无线调试,获取新的端口号。

  • 其他报错:查阅小白调试助手官方的使用说明或 GitHub 仓库的 Issue 区寻求解决方案。


xoyozo 3 天前
154
  1. 安装“腾讯手机管家”或其它支持按关键词设置黑名单的垃圾信息过滤工具

  2. 打开手机设置 - App - 信息 - 未知与过滤信息 - 选择“腾讯手机管家”

  3. 打开“腾讯手机管家”- 垃圾短信过滤 - 自定义短信拦截 - 黑名单 - 添加关键词

    (每次添加一个词就确定,如果填写多个表示同一条短信中同时包含这些关键词)

xoyozo 22 天前
250

AsNoTracking 设置未追踪查询

var customers = dbContext.Customers.AsNoTracking().ToList();

这对于只读查询非常有用,因为它可以减少内存使用并提高性能,因为它不需要维护实体的更改跟踪信息。

何时需要 AsNoTracking()?


ExecuteDelete 和 ExecuteUpdate 批量操作

context.Logs.Where(c => c.Time < new DateTime(2000, 1, 1)).ExecuteDelete();

从 EF Core 7 开始,ExecuteDelete 和 ExecuteUpdate 是官方原生支持的批量操作方法。直接操作数据库,不需要调用 SaveChanges():不加载实体到内存,减少内存消耗和网络往返。

若需要分页删除和大批量插入,或在高频、大规模场景,推荐使用 Zack.EFCore.Batch

context.Logs.Where(c => c.Time < new DateTime(2000, 1, 1)).DeleteRangeAsync(batchSize: 1000);


考虑用 Union 代替 OR

// Where 后行数多时(如分页前)用 OR
var q = db.dt_crm__contract.AsNoTracking();
q = q.Where(c => c.dt_crm__customer.SalesmanId == uid || myIns.Contains(c.IndustryId));

// 用于合并的 q1、q2 的行数少时用 Union
var q1 = db.dt_crm__contract.AsNoTracking().Where(c => c.dt_crm__customer.SalesmanId == uid);
var q2 = db.dt_crm__contract.AsNoTracking().Where(c => myIns.Contains(c.IndustryId));
var q = q1.Union(q2);


“ToDictionary + Count”之前先 Select

// 不推荐
var dic = q.GroupBy(c => c.Date)
    .ToDictionary(k => k.Key, v => v.Count());
// 推荐
var dic = q.GroupBy(c => c.Date)
    .Select(g => new { g.Key, Count = g.Count() })
    .ToDictionary(k => k.Key, v => v.Count);



xoyozo 1 个月前
309

image.png

现象:

VS2022 的“管理 nuget 程序包”页面的“更新”和“已安装”选项卡无限循环加载刷新,状态栏一直循环显示“正在还原 NuGet 程序包”、“就绪”。点开来有很多“正在加载 IntelliSense 任务已成功完成”。我有很多解决方案和项目,只有其中一个出现上述情况。

解决方法:

image.png

点击“设置”,在“常规”页面点击“清除所有 NuGet 存储”。

image.png

xoyozo 1 个月前
255
  1. 临界区与 lock 关键字

    核心作用:

    通过将多线程访问串行化,保护共享资源或代码段。lock 关键字是 Monitor 类的语法糖,提供异常安全的临界区实现。

    实现示例:

    // 创建私有静态只读对象
    // private static readonly object _lockObj = new object();
    private static readonly System.Threading.Lock _locker = new(); // .NET 9+ 推荐使用 Lock 类型,避免传统 object 的性能损耗
    
    public void ThreadSafeMethod()
    {
        lock (_lockObj) 
        {
            // 临界区代码(每次仅一个线程可进入)
        }
    }

    超时机制:

    高并发场景可结合 Monitor.TryEnter 设置超时,避免无限等待:


    if (Monitor.TryEnter(lockObject, TimeSpan.FromSeconds(1)))
    {
        try { /* 操作 */ }
        finally { Monitor.Exit(lockObject); }
    }

    关键特性:

    用户态锁(无内核切换开销)

    自动调用Monitor.Enter和Monitor.Exit

    必须使用专用私有对象作为锁标识

    注意事项:

    ❌ 避免锁定this、Type实例或字符串(易引发死锁)

    ❌ 避免嵌套锁(需严格按顺序释放)

    ✅ 推荐readonly修饰锁对象

    ❌ lock 不适用于异步代码(async/await),需使用 SemaphoreSlim 实现异步锁

    lock 示例

     

  2. 互斥锁(Mutex)

    核心作用:

    系统级内核锁,支持跨进程同步,但性能开销较高(用户态/内核态切换)。

    实现示例:

    using var mutex = new Mutex(false, "Global\\MyAppMutex");
    
    try 
    {
        // 等待锁(最大等待时间500ms)
        if (mutex.WaitOne(500)) 
        {
            // 临界区代码
        }
    }
    finally 
    {
        if (mutex != null)
        {
            mutex.ReleaseMutex();
        }
    }

    关键特性:

    支持跨应用程序域同步

    线程终止时自动释放锁

    支持命名互斥体(系统全局可见)

    适用场景:

    单实例应用程序控制

    进程间共享文件访问

    硬件设备独占访问

    Mutex 示例

     

  3. 信号量(Semaphore)

    核心作用:

    通过许可计数器控制并发线程数,SemaphoreSlim为轻量级版本(用户态实现)。

    实现对比:

    类型
    跨进程
    性能
    最大许可数
    Semaphore
    ✔️

    系统限制
    SemaphoreSlim


    Int32.Max

    代码示例:

    // 创建初始3许可、最大5许可的信号量
    var semaphore = new SemaphoreSlim(3, 5);
    
    semaphore.Wait();  // 获取许可
    try 
    {
        // 资源访问代码
    }
    finally 
    {
        semaphore.Release();
    }

    异步编程

    private readonly SemaphoreSlim _asyncLock = new(1, 1);
    public async Task UpdateAsync()
    {
        await _asyncLock.WaitAsync();
        try { /* 异步操作 */ }
        finally { _asyncLock.Release(); }
    }

    典型应用:

    数据库连接池(限制最大连接数)

    API 请求限流

    批量任务并发控制

    Semaphore 示例

     

  4. 事件(Event)

    核心机制:

    通过信号机制实现线程间通知,分为两种类型:

    类型
    信号重置方式
    唤醒线程数
    AutoResetEvent
    自动
    单个
    ManualResetEvent
    手动
    所有

    使用示例:

    var autoEvent = new AutoResetEvent(false);
    
    // 等待线程
    Task.Run(() => 
    {
        autoEvent.WaitOne();
        // 收到信号后执行
    });
    
    // 信号发送线程
    autoEvent.Set();  // 唤醒一个等待线程

    高级用法:

    配合WaitHandle.WaitAll实现多事件等待

    使用ManualResetEventSlim提升性能

    AutoResetEvent 示例

     

  5. 读写锁(ReaderWriterLockSlim)

    核心优势:

    实现读写分离的并发策略,适合读多写少场景(如缓存系统)。

    锁模式对比:

    模式
    并发性
    升级支持
    读模式(EnterReadLock)
    多线程并发读

    写模式(EnterWriteLock)
    独占访问

    可升级模式
    单线程读→写
    ✔️

    代码示例:

    var rwLock = new ReaderWriterLockSlim();
    
    // 读操作
    rwLock.EnterReadLock();
    try 
    {
        // 只读访问
    }
    finally 
    {
        rwLock.ExitReadLock();
    }
    
    // 写操作
    rwLock.EnterWriteLock();
    try 
    {
        // 排他写入
    }
    finally 
    {
        rwLock.ExitWriteLock();
    }

    最佳实践:

    优先使用ReaderWriterLockSlim(旧版有死锁风险)

    避免长时间持有读锁(可能饿死写线程)

    ReaderWriterLockSlim 示例

  6. 原子操作(Interlocked)

    原理:

    通过CPU指令实现无锁线程安全操作。

    常用方法:

    int counter = 0;
    Interlocked.Increment(ref counter);      // 原子递增
    Interlocked.Decrement(ref counter);      // 原子递减
    Interlocked.CompareExchange(ref value, newVal, oldVal);  // CAS操作

    适用场景:

    简单计数器

    标志位状态切换

    无锁数据结构实现

     

  7. 自旋锁(SpinLock)

    核心特点:

    通过忙等待(busy-wait)避免上下文切换,适用极短临界区(<1微秒)。

    实现示例:

    private SpinLock _spinLock = new SpinLock();
    
    public void CriticalOperation()
    {
        bool lockTaken = false;
        try 
        {
            _spinLock.Enter(ref lockTaken);
            // 极短临界区代码
        }
        finally 
        {
            if (lockTaken) _spinLock.Exit();
        }
    }

    优化技巧:

    单核CPU需调用Thread.SpinWait或Thread.Yield

    配合SpinWait结构实现自适应等待

     

  8. 同步机制对比指南

    机制
    跨进程
    开销级别
    最佳适用场景
    lock


    通用临界区保护
    Mutex
    ✔️

    进程间资源独占
    Semaphore
    ✔️

    并发数限制(跨进程)
    SemaphoreSlim


    并发数限制(进程内)
    ReaderWriterLockSlim


    读多写少场景
    SpinLock

    极低
    纳秒级临界区
    Interlocked
    -无锁
    简单原子操作

选择原则:

  1. 优先考虑用户态锁(lock/SpinLock/SemaphoreSlim)

  2. 跨进程需求必须使用内核对象(Mutex/Semaphore)

  3. 读写比例超过10:1时考虑读写锁

  4. 自旋锁仅用于高频短操作(如链表指针修改)

通过以上结构化的分类和对比,开发者可以更精准地选择适合特定场景的线程同步方案。建议在实际使用中配合性能分析工具(如BenchmarkDotNet)进行量化验证。

💡 ASP.NET 的异步编程(async/await)本质是单进程内的线程调度,不算“跨进程”。每个 IIS 应用程序池对应一个独立的工作进程(w3wp.exe),不同用户访问同一应用程序池下的 ASP.NET 网站,两者的请求均由同一个 w3wp.exe 进程处理。可能跨进程的场景有:Web Garden 配置、多应用程序池部署等。

在 C# 中,除了常规锁机制(如 lock、Mutex、Semaphore 等),还有一些内置类型通过内部锁或无锁设计实现线程安全。以下是常见的几类:

  1. 线程安全集合(System.Collections.Concurrent)这些集合通过细粒度锁或无锁算法(如 CAS)实现线程安全,适合高并发场景。

    • ConcurrentDictionary:分段锁机制,将数据分片存储,每个分片独立加锁,减少锁竞争。

    • ConcurrentQueue / ConcurrentStack基于原子操作(Interlocked)保证线程安全。

    • ConcurrentBag:每个线程维护本地存储,减少争用,适合频繁添加和移除的场景。

    • BlockingCollection:基于 ConcurrentQueue 和信号量(SemaphoreSlim)实现生产-消费者模式,支持阻塞和超时。

  2. 不可变集合(System.Collections.Immutable) 通过数据不可变性实现线程安全(无需锁),每次修改返回新对象。

  3. Lazy 的线程安全初始化(Lazy<T>) 通过锁或 Interlocked 确保延迟初始化的线程安全。

  4. 通道(System.Threading.Channels)用于异步生产-消费者模型,内部通过锁和信号量管理容量限制。

  5. 内存缓存(System.Runtime.Caching.MemoryCache)内部使用锁保护共享状态,确保线程安全。

  6. 原子操作类型(Interlocked 类、Volatile 关键字、Unsafe 类)通过 CPU 指令实现无锁线程安全。

  7. 其他同步工具(Barrier、CountdownEvent)虽然不是严格意义上的锁,但用于协调线程。

xoyozo 1 个月前
491

在 .NET Framework 的缓存管理中,cacheMemoryLimitMegabytes 是一个关键配置属性,用于控制内存缓存(MemoryCache)实例的最大内存占用。以下是其具体用法及实现细节:

  1. 基本定义与作用

    • 功能:通过 cacheMemoryLimitMegabytes 可设置 MemoryCache 实例允许占用的最大内存(单位:MB)。若缓存数据超过此限制,系统会自动淘汰旧条目。

    • 默认值:默认值为 0,表示缓存基于计算机的物理内存自动管理(例如根据可用内存动态调整)。

  2. 配置方式

    • 通过配置文件(web.config)

      在 web.config 的 <system.runtime.caching> 节点下配置 namedCaches,示例:

      <configuration>
        <system.runtime.caching>
          <memoryCache>
            <namedCaches>
              <add 
                name="Default" 
                cacheMemoryLimitMegabytes="500" 
                physicalMemoryLimitPercentage="50" 
                pollingInterval="00:05:00" />
            </namedCaches>
          </memoryCache>
        </system.runtime.caching>
      </configuration>

      参数说明:

      • cacheMemoryLimitMegabytes:最大内存限制(例如 500 表示 500MB)。

      • physicalMemoryLimitPercentage:允许使用的物理内存百分比(可选)。

      • pollingInterval:缓存清理策略的轮询间隔(例如每5分钟检查一次)。

    • 通过代码动态配置

      在初始化 MemoryCache 时,通过 NameValueCollection 传递参数:

      var config = new NameValueCollection
      {
          { "cacheMemoryLimitMegabytes", "500" },
          { "physicalMemoryLimitPercentage", "50" },
          { "pollingInterval", "00:05:00" }
      };
      var cache = new MemoryCache("CustomCache", config);

      此方式适用于需要动态调整缓存策略的场景。

  3. 注意事项

    • 优先级规则:

      若同时配置了 cacheMemoryLimitMegabytes 和 physicalMemoryLimitPercentage,系统会选择两者中较小的值作为限制。

    • 分布式缓存兼容性:

      此属性仅适用于进程内缓存(如 MemoryCache),若使用 Redis 等分布式缓存需通过其独立配置管理内存。

    • 监控与调试:

      建议结合性能计数器(如 ASP.NET Applications 类别下的 Cache Total Entries)或日志记录模块(参考 web.config 的 <system.diagnostics> 配置)监控实际内存占用。

  4. 应用场景示例

    场景:一个电商网站需要缓存商品目录数据,限制最大内存为 1GB。

    配置实现:

    <add 
      name="ProductCatalogCache" 
      cacheMemoryLimitMegabytes="1024" 
      pollingInterval="00:10:00" />

    代码调用:

    var productCatalog = MemoryCache.Default["ProductCatalog"];
  5. 常见问题

    1. Q:设置为 0 时缓存会无限制增长吗?

      A:不会。此时缓存基于系统物理内存动态管理,通常上限为总内存的 70%-90%。

    2. Q:如何验证配置已生效?

      A:可通过 MemoryCache.GetCount() 统计条目数量,或使用性能监视器跟踪内存占用。

xoyozo 2 个月前
379
zoom显示
1洲名
2洲名
3国名
4国名、首都
5省名
6省名、省会
7地级市
8地级市名、县级市名
9地级市名、县级市名、部分街道/镇名
10
地级市名、县级市名、部分街道/镇名
11
地级市名、县级市名、部分街道/镇名、部分村名
12
地级市名、县级市名、部分街道/镇名、部分村名
13
地标
14
村名
15
小区名
16
建筑物轮廓
17
建筑物幢号

设置缩放级别:

map.centerAndZoom(new T.LngLat(108.95, 34.27), 4); // 默认显示整个中国地图、省级边界线
map.setMinZoom(2); // 世界地图
map.setMaxZoom(8); // 区/县/市


xoyozo 2 个月前
286
  1. 打开“任务计划程序”(taskschd.msc)

    image.png

  2. 点击右侧“创建任务”

    image.png

  3. 填写“名称”

    image.png

  4. “安全选项”根据实际情况设置

    如果选择“不管用户是否登录都要运行”,则启动成功后不会显示窗口(任务管理器中可见进程)

    如果选择“只在用户登录时运行”启动成功后会显示窗口,但系统重启后需要进入系统才能运行此计划

  5. “触发器”新建,勾选“重复任务间隔”选最短,“持续时间”无限期,并取消“任务的执行时间超过此值则停止执行”

    image.png

  6. “操作”新建,启动程序,浏览程序或脚本

    image.png

  7. “设置”请勿启动新实例(只判断它启动的实例,不判断手动打开的或开机启动的实例),其它选项按需设置

    image.png

  8. 设置完成

    image.png


设置完成后查看“上次运行结果”。

尚未运行,显示:(0xC000013A)

第一次运行,显示:正在运行任务。(0x41301)

从第二次起,显示:操作员或系统管理员拒绝了请求。(0x800710E0)


xoyozo 2 个月前
552
  1. 在解决方案资源管理器中找到 Properties/AssemblyInfo.cs 文件。该文件存放程序集版本信息。

  2. 修改版本号格式

    将以下代码片段中的 AssemblyVersion 改为使用星号通配符(建议保留主版本和次版本号):

    [assembly: AssemblyVersion("1.0.*")]  // 自动生成构建号和修订号
    // [assembly: AssemblyFileVersion("1.0.0.0")] // 注释或删除此行
  3. 关闭确定性构建

    用文本编辑器打开 .csproj 项目文件,在 <PropertyGroup> 标签内添加:

    <Deterministic>false</Deterministic>

    此设置允许 MSBuild 生成动态版本号。

最终生成的版本号示例: 1.0.9238.28518

其中,Major 与 Minor 是固定的,Build 是2000年1月1日至今的天数,Revision 是今天的秒数 / 2 所得的值。(为了防止数值超过 65535)


程序中获取版本号:

var version = Assembly.GetExecutingAssembly().GetName().Version;


从版本号获取发布时间:

DateTime versionTime = new DateTime(2000, 1, 1).AddDays(version.Build).AddSeconds(version.Revision * 2);


查看 .NET Core / .NET 5+ 实现自动版本号的方法


xoyozo 2 个月前
419

通常,我们在更新一条数据库记录时,EF 先取出这一条记录:

var log = DbContext.MyTable.Find(id);

然后赋值字段并保存:

log.Result = "OK";
DbContext.SaveChanges();

这样就会产生两次数据库查询。


我们尝试用 Attach 方法。

先创建一个仅包含主键的对象:

var log  = new MyTable { Id = id };

将对象附加到上下文:

DbContext.MyTable.Attach(log);

然后更新需要更新的字段:

log.Result = "OK";
DbContext.SaveChanges();

这样,能在保留其它字段值的前提下,减少一次数据库查询。

但是需要注意的是:

当某非 null 字段需要恢复默认值时,EF 会忽略这个更改。(可能会因 EF 版本等原因有不同的结论)

举个例子:

某记录有个 int 型字段 a,在数据库中这个记录的 a 的值为 1,但 C# 中 int 型的默认值为 0,所以当 Attach 附加这个对象后,如果重新设置 log.a 为 0,那么保存后 a 的值仍为 1。


还有一种写法,利用 ExecuteUpdate 方法:

var affectedRows = DbContext.MyTable
  .Where(c => c.Id == id)
  .ExecuteUpdate(setters => setters
    .SetProperty(c => c.Result, "OK")
  );

返回匹配的行数。

这种写法不会遇到“恢复为默认值不生效”的问题,推荐使用。

xoyozo 3 个月前
419