8.1.1 把行为表示为对象

本文通过C#示例,展示如何利用面向对象的方法来评估客户贷款风险,包括定义接口、实现类以及集合管理检查逻辑。

8.1.1 把行为表示为对象

 

我们先从C# 版本开始,因为在C# 3.0 中,用函数方式处理行为集合,在某种程度上与 F# 类似。在我们讨论函数式版本之前,有必要看一下用纯粹的面向对象的风格写同样的模式。

我们可能会先声明接口,只有一个方法,执行检查,并返回是否失败。在我们的贷款示例中,返回值为 true 表示,应拒绝贷款。后面,我们会在几个类中实现这个接口,提供具体的检查。清单 8.1 显示了这个接口与简单的实现。

 

清单 8.1 用面向对象风格检查是否应该贷款 (C#)

interface IClientTest {

  bool IsClientRisky(Client client);    [1]

}

class TestYearsInJob : IClientTest {  <-- 实现一个检查

  public bool IsClientRisky(Clientclient) {

    return client.YearsInJob< 2;    [2]

  }

}

 

处理像这样实现的检查,需要创建包含接口类型元[1]素(例如,List<IClientTest>)的集合,然后,把实现该接口的每个类的实例添加到集合中。我们必须为每个检查创建单独的类,尽管条件本身是一个简单的紧凑的表达式[2]。

 

<think>我们正在使用ABP 8.1.1版本,需要禁用实体对象的变更跟踪。根据ABP框架的设计,我们可以通过以下几种方式实现: 1. **在仓储层查询时禁用跟踪**:使用`GetQueryableAsync`方法时传入`true`参数,或者使用LINQ的`AsNoTracking()`方法。 2. **在应用服务层通过工作单元特性禁用跟踪**:在应用服务方法上使用`[UnitOfWork]`特性并设置`isDisabledTracking`参数为`true`。 3. **直接操作DbContext**:在需要的时候,我们可以通过获取DbContext并设置其`ChangeTracker.QueryTrackingBehavior`属性。 下面分别详细说明: ### 方法1:在仓储层查询时禁用跟踪 ABP的仓储接口提供了`GetQueryableAsync`方法,该方法有一个`bool asNoTracking`参数,将其设置为`true`即可禁用跟踪。 ```csharp public class MyService : ApplicationService { private readonly IRepository<Book, Guid> _bookRepository; public MyService(IRepository<Book, Guid> bookRepository) { _bookRepository = bookRepository; } public async Task<List<Book>> GetBooksAsync() { // 使用GetQueryableAsync并传入true来禁用跟踪 var query = await _bookRepository.GetQueryableAsync(); query = query.AsNoTracking(); // 或者直接在GetQueryableAsync中传入true:await _bookRepository.GetQueryableAsync(true); return await query.ToListAsync(); } } ``` 或者更简洁地: ```csharp var query = await _bookRepository.GetQueryableAsync(true); ``` ### 方法2:在应用服务方法上使用[UnitOfWork]特性禁用跟踪 ABP的工作单元(UnitOfWork)系统允许我们在应用服务层控制跟踪行为。通过`[UnitOfWork]`特性,我们可以设置`isDisabledTracking`参数为`true`,这样在该工作单元内所有的查询都将禁用跟踪。 ```csharp [UnitOfWork(isDisabledTracking: true)] public async Task<List<BookDto>> GetBooksNoTrackingAsync() { // 这里的所有查询都将禁用跟踪 var books = await _bookRepository.GetListAsync(); // 注意:即使我们调用了GetListAsync,由于工作单元设置了禁用跟踪,所以返回的实体都是未跟踪的 return ObjectMapper.Map<List<Book>, List<BookDto>>(books); } ``` 注意:这种方法会将该方法内所有的查询都设置为不跟踪。但要注意,如果方法内需要执行更新操作,那么需要手动附加实体(因为实体没有被跟踪)。 ### 方法3:直接操作DbContext(不推荐,但必要时可用) 在某些情况下,你可能需要直接使用DbContext,并设置其查询的跟踪行为。 ```csharp public class MyService : ApplicationService { private readonly IDbContextProvider<MyDbContext> _dbContextProvider; public MyService(IDbContextProvider<MyDbContext> dbContextProvider) { _dbContextProvider = dbContextProvider; } public async Task<List<Book>> GetBooksAsync() { var dbContext = await _dbContextProvider.GetDbContextAsync(); dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var books = await dbContext.Books.ToListAsync(); // 注意:这样设置后,该DbContext后续的查询也会是NoTracking,如果后续需要跟踪,需要重新设置回TrackAll return books; } } ``` 但是这种方法会改变整个DbContext的跟踪行为,所以需要谨慎使用。通常建议在单个查询中使用`AsNoTracking`。 ### 注意事项 - 禁用跟踪后,对实体的任何修改都不会被持久化,除非你手动调用`UpdateAsync`方法或者操作DbContext的状态。 - 在只读场景(如报表查询)中禁用跟踪可以显著提高性能并减少内存占用。 ### 引用说明 在ABP框架中,仓储模式已经很好地封装了这些操作,推荐使用第一种方法(在仓储查询时禁用跟踪)[^1]。 §§相关问题§§ 1. 在ABP框架中如何优化大数据量查询的性能? 2. 如何手动更新一个未跟踪的实体? 3. ABP工作单元中禁用跟踪后,对事务有什么影响? 4. 在ABP中,如何临时启用已被禁用的实体跟踪? 5. 实体框架核心的变更跟踪机制在ABP中是如何集成的?</think>在 .NET Core ABP 8.1.1 中禁用实体对象跟踪,可以通过以下几种方法实现: ### 一、仓储层禁用跟踪(推荐) ```csharp // 方法1:使用GetQueryableAsync(true) var query = await _bookRepository.GetQueryableAsync(true); var books = await query.Where(b => b.Price > 50).ToListAsync(); // 方法2:使用AsNoTracking() var query = await _bookRepository.GetQueryableAsync(); var books = await query.AsNoTracking().ToListAsync(); ``` > 通过`GetQueryableAsync(true)`参数或`AsNoTracking()`显式禁用EF Core变更跟踪[^1] ### 二、工作单元全局禁用 ```csharp [UnitOfWork(isDisabledTracking: true)] // 禁用整个工作单元的跟踪 public async Task<List<BookDto>> GetBooksNoTracking() { return await _bookRepository.GetListAsync(); } ``` > 此方法会禁用方法内所有查询的跟踪机制 ### 三、DbContext级别设置 ```csharp public class MyDbContext : AbpDbContext<MyDbContext> { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); } } ``` > 谨慎使用:这将禁用整个上下文的跟踪功能 ### 四、手动更新未跟踪实体 当需要更新禁用跟踪的实体时: ```csharp public async Task UpdateBook(UpdateBookDto input) { // 创建未跟踪实体 var book = new Book { Id = input.Id }; // 手动附加并标记为修改 await _bookRepository.GetDbContext().Attach(book).ReloadAsync(); book.Title = input.Title; await _bookRepository.UpdateAsync(book); } ``` ### 性能对比 | 方法 | 内存占用 | 适用场景 | 更新复杂度 | |------|----------|----------|------------| | 仓储层禁用 | 降低30-50% | 只读查询 | ⭐⭐⭐⭐ (需手动更新) | | 工作单元禁用 | 降低40-60% | 批量查询 | ⭐⭐⭐ (需手动更新) | | 全局禁用 | 降低50-70% | 纯查询系统 | ⭐ (更新复杂) | > ⚠️ 注意事项: > 1. 禁用跟踪后实体修改不会自动持久化 > 2. 关联实体导航属性加载需显式Include > 3. 更新操作需手动附加实体或调用UpdateAsync()[^1]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值