LINQ 增强、命名查询过滤器、复杂类型 JSON 映射、Aspire 持续改进------数据访问和云原生开发的最新进展
版本定位
适用版本:.NET 10 | EF Core 10 | Aspire 13.1 前置知识:EF Core 基础、Aspire 基础
背景
EF Core 10 在数据访问方面带来了多项重大改进,包括复杂类型 JSON 映射、命名查询过滤器、批量操作增强等。Aspire 13.1 则继续改进云原生开发体验,新增 Dashboard 增强、Azure/AWS 集成改进以及 Redis 作为 LLM 缓存等能力。
新特性一览
| 特性 | 简述 | 实用性 |
|---|---|---|
| 复杂类型 JSON 映射 | 将复杂类型映射为 JSON 列 | ⭐⭐⭐⭐⭐ |
| 命名查询过滤器 | 多个可独立控制的查询过滤器 | ⭐⭐⭐⭐⭐ |
| DbSet 参数支持 | 集合参数化查询 | ⭐⭐⭐⭐ |
| ExecuteUpdate/ExecuteDelete 增强 | 批量操作支持更多场景 | ⭐⭐⭐⭐⭐ |
| 交错式 ID 改进 | 更灵活的主键生成策略 | ⭐⭐⭐⭐ |
| SQL Server TIME 类型支持 | 原生时间类型映射 | ⭐⭐⭐ |
| 值比较器改进 | 更精确的变更检测 | ⭐⭐⭐⭐ |
| 查询翻译改进 | 更多 LINQ 操作翻译为 SQL | ⭐⭐⭐⭐ |
| 安全改进 | 默认禁用敏感数据日志 | ⭐⭐⭐⭐ |
| Aspire Dashboard 增强 | 更好的可观测性体验 | ⭐⭐⭐⭐⭐ |
| Aspire + Azure 集成 | Azure 服务深度集成 | ⭐⭐⭐⭐ |
| Aspire + AWS 集成 | AWS 服务深度集成 | ⭐⭐⭐ |
| Redis 作为 LLM 缓存 | AI 应用缓存方案 | ⭐⭐⭐⭐ |
| Aspire 模板改进 | 更多项目模板 | ⭐⭐⭐ |
EF Core 10 新特性详解
1. 复杂类型 JSON 映射(Complex Type JSON Mapping)
之前的做法:复杂类型需要单独的表或手动序列化
// EF Core 9 及之前
public class Order
{
public int Id { get; set; }
// 需要单独的表存储地址
public int ShippingAddressId { get; set; }
public Address ShippingAddress { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
EF Core 10 的做法:将复杂类型直接映射为 JSON 列
// EF Core 10
public class Order
{
public int Id { get; set; }
// 复杂类型直接存储为 JSON 列
public Address ShippingAddress { get; set; }
public Address BillingAddress { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
// 配置
modelBuilder.Entity<Order>().ComplexProperty(o => o.ShippingAddress);
modelBuilder.Entity<Order>().ComplexProperty(o => o.BillingAddress);
数据库表结构对比:
| 方案 | 表结构 | 查询性能 | 存储效率 |
|---|---|---|---|
| 旧方案(关联表) | Order + Address 表 | JOIN 查询 | 正常 |
| 新方案(JSON 列) | Order 表(含 JSON 列) | 单表查询 | 更高 |
查询示例:
// 查询 JSON 列中的属性
var orders = await context.Orders
.Where(o => o.ShippingAddress.City == "Beijing")
.ToListAsync();
// 更新 JSON 列中的属性
await context.Orders
.Where(o => o.Id == 1)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.ShippingAddress.City, "Shanghai"));
2. 命名查询过滤器
之前的做法:使用 HasQueryFilter,每个实体只能有一个
// EF Core 9 及之前
public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
// 只能有一个过滤器
builder.HasQueryFilter(p => p.IsActive);
}
}
EF Core 10 的做法:命名查询过滤器,支持多个
// EF Core 10
public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
// 可以有多个命名过滤器
builder.HasQueryFilter("ActiveFilter", p => p.IsActive);
builder.HasQueryFilter("RecentFilter", p => p.CreatedAt > DateTime.Now.AddDays(-30));
}
}
// 使用时可以禁用特定过滤器
var allProducts = await context.Products
.IgnoreQueryFilters("ActiveFilter") // 只禁用 ActiveFilter
.ToListAsync();
3. DbSet 参数支持
之前的做法:使用 Contains 时需要构建列表
// EF Core 9 及之前
var ids = new List<int> { 1, 2, 3, 4, 5 };
var products = await context.Products
.Where(p => ids.Contains(p.Id))
.ToListAsync();
EF Core 10 的做法:直接使用 DbSet 作为参数
// EF Core 10
var categoryIds = context.Categories
.Where(c => c.Name.StartsWith("Electronics"))
.Select(c => c.Id);
var products = await context.Products
.Where(p => categoryIds.Contains(p.CategoryId))
.ToListAsync();
4. ExecuteUpdate/ExecuteDelete 增强
之前的做法:批量操作功能有限
// EF Core 9 及之前
await context.Products
.Where(p => p.Price < 10)
.ExecuteUpdateAsync(s => s.SetProperty(p => p.Price, p => p.Price * 1.1m));
EF Core 10 的做法:支持更复杂的批量操作
// EF Core 10 - 支持多个 Set 操作
await context.Products
.Where(p => p.Price < 10)
.ExecuteUpdateAsync(s => s
.SetProperty(p => p.Price, p => p.Price * 1.1m)
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow)
.SetProperty(p => p.NeedsReview, true));
// 支持删除并返回删除的实体
var deletedProducts = await context.Products
.Where(p => p.IsDiscontinued)
.ExecuteDeleteAndReturnAsync();
5. 交错式 ID 改进(Interleaved ID)
// EF Core 10 - 更灵活的主键生成
public class Order
{
// 交错式 ID: tenantId + sequence
[Key]
public Guid Id { get; set; }
public int TenantId { get; set; }
}
// 配置交错式 ID
modelBuilder.Entity<Order>()
.Property(o => o.Id)
.HasInterleavedId(o => o.TenantId);
6. SQL Server TIME 类型支持
// EF Core 10 - 原生 TIME 类型映射
public class StoreHours
{
public int Id { get; set; }
public TimeOnly OpenTime { get; set; }
public TimeOnly CloseTime { get; set; }
}
// 查询
var openStores = await context.StoreHours
.Where(s => s.OpenTime <= TimeOnly.FromDateTime(DateTime.Now))
.Where(s => s.CloseTime >= TimeOnly.FromDateTime(DateTime.Now))
.ToListAsync();
7. 值比较器改进
// EF Core 10 - 更精确的变更检测
public class Money
{
public decimal Amount { get; set; }
public string Currency { get; set; }
}
// 自定义值比较器
public class MoneyComparer : ValueComparer<Money>
{
public MoneyComparer() : base(
(a, b) => a.Amount == b.Amount && a.Currency == b.Currency,
m => m.Amount.GetHashCode() ^ m.Currency.GetHashCode(),
m => new Money { Amount = m.Amount, Currency = m.Currency })
{
}
}
// 配置
modelBuilder.Entity<Product>()
.Property(p => p.Price)
.Metadata.SetValueComparer(new MoneyComparer());
8. 查询翻译改进
// EF Core 10 - 更多 LINQ 操作翻译为 SQL
// 窗口函数支持
var rankedProducts = await context.Products
.Select(p => new
{
p.Name,
p.Price,
Rank = EF.Functions.RankOver(
EF.Functions.PartitionBy(p.Category),
EF.Functions.OrderBy(p.Price))
})
.ToListAsync();
// 更复杂的 GROUP BY
var categoryStats = await context.Products
.GroupBy(p => p.Category)
.Select(g => new
{
Category = g.Key,
Count = g.Count(),
AveragePrice = g.Average(p => p.Price),
MinPrice = g.Min(p => p.Price),
MaxPrice = g.Max(p => p.Price)
})
.ToListAsync();
9. 安全改进
// EF Core 10 - 默认禁用敏感数据日志
// 之前需要手动配置
optionsBuilder.EnableSensitiveDataLogging(false); // 现在是默认行为
// 如果需要启用,必须显式声明
optionsBuilder.EnableSensitiveDataLogging(true); // 需要显式启用
Aspire 13.1 新特性详解
1. Dashboard 增强
┌─────────────────────────────────────────────────────────┐
│ .NET Aspire Dashboard │
├─────────────────────────────────────────────────────────┤
│ Resources │ Console │ Logs │ Traces │ Metrics │ AI │
├─────────────────────────────────────────────────────────┤
│ api │ Running │ 127.0.0.1:5000 │
│ web │ Running │ 127.0.0.1:5001 │
│ cache │ Running │ 127.0.0.1:6379 │
│ db │ Running │ 127.0.0.1:5432 │
│ mq │ Running │ 127.0.0.1:5672 │
│ llm-cache │ Running │ 127.0.0.1:6380 │
└─────────────────────────────────────────────────────────┘
新增功能:
-
AI 追踪面板:可视化 LLM 调用链路和 Token 消耗
-
资源依赖图:直观展示服务间依赖关系
-
性能指标仪表盘:实时监控 CPU、内存、请求量
2. Aspire + Azure 集成
var builder = DistributedApplication.CreateBuilder(args);
// Azure 服务深度集成
var storage = builder.AddAzureStorage("storage");
var cosmos = builder.AddAzureCosmosDB("cosmos")
.AddDatabase("mydb");
var serviceBus = builder.AddAzureServiceBus("servicebus");
var appInsights = builder.AddAzureApplicationInsights("insights");
// 自动配置连接字符串和遥测
builder.AddProject<Projects.MyApi>("api")
.WithReference(storage)
.WithReference(cosmos)
.WithReference(serviceBus)
.WithReference(appInsights);
3. Aspire + AWS 集成
var builder = DistributedApplication.CreateBuilder(args);
// AWS 服务支持
var dynamodb = builder.AddAWSDynamoDB("dynamodb");
var sqs = builder.AddAWSSqs("sqs");
var s3 = builder.AddAWSS3("s3");
builder.AddProject<Projects.MyApi>("api")
.WithReference(dynamodb)
.WithReference(sqs)
.WithReference(s3);
4. Redis 作为 LLM 缓存
var builder = DistributedApplication.CreateBuilder(args);
// Redis 作为 LLM 缓存
var redis = builder.AddRedis("llm-cache");
// 配置 LLM 服务使用 Redis 缓存
builder.AddProject<Projects.MyAiService>("ai")
.WithReference(redis)
.WithEnvironment("LLM_CACHE_TTL", "3600");
使用示例:
// AI 服务中使用 Redis 缓存
public class AiService
{
private readonly IDatabase _redis;
private readonly IChatClient _chatClient;
public AiService(IDatabase redis, IChatClient chatClient)
{
_redis = redis;
_chatClient = chatClient;
}
public async Task<string> GetCompletion(string prompt)
{
// 检查缓存
var cached = await _redis.StringGetAsync($"llm:{prompt.GetHashCode()}");
if (cached.HasValue)
return cached.ToString();
// 调用 LLM
var result = await _chatClient.CompleteAsync(prompt);
// 写入缓存
await _redis.StringSetAsync(
$"llm:{prompt.GetHashCode()}",
result.Message.Content,
TimeSpan.FromHours(1));
return result.Message.Content;
}
}
5. Aspire 模板改进
# 新增模板
dotnet new list aspire
# Aspire 项目模板
dotnet new aspire-starter # 完整微服务模板
dotnet new aspire-api # API 服务模板
dotnet new aspire-redis # Redis 缓存模板
dotnet new aspire-ai # AI 服务模板
实战场景
EF Core 10 复杂类型 JSON 映射适合的场景
// 配置信息存储
public class AppConfig
{
public int Id { get; set; }
public AppSettings Settings { get; set; }
public NotificationConfig Notifications { get; set; }
}
modelBuilder.Entity<AppConfig>()
.ComplexProperty(c => c.Settings)
.ComplexProperty(c => c.Notifications);
Aspire 适合的场景
// 微服务架构
var builder = DistributedApplication.CreateBuilder(args);
// 数据库服务
var db = builder.AddPostgreSQL("db")
.AddDatabase("mydb");
// 缓存服务
var cache = builder.AddRedis("cache");
// 消息队列
var mq = builder.AddRabbitMQ("messaging");
// API 服务
var api = builder.AddProject<Projects.MyApi>("api")
.WithReference(db)
.WithReference(cache)
.WithReference(mq);
// Web 前端
builder.AddProject<Projects.MyWeb>("web")
.WithReference(api);
迁移建议
EF Core 10 迁移
# 1. 更新 NuGet 包
dotnet add package Microsoft.EntityFrameworkCore --version 10.0.0
# 2. 创建迁移
dotnet ef migrations add InitialCreate
# 3. 应用迁移
dotnet ef database update
Aspire 13.1 迁移
# 1. 更新 Aspire 模板
dotnet new install Aspire.ProjectTemplates
# 2. 更新项目引用
dotnet add package Aspire.Hosting --version 13.3.3
一句话总结
EF Core 10 的复杂类型 JSON 映射和命名过滤器,加上 Aspire 13.1 的 Azure/AWS 集成与 LLM 缓存支持,让数据访问和云原生 AI 开发更加强大。
官方文档
📦 示例代码:.NET 新特性巡礼全系列配套示例代码(含 dotnet 8/9/10)
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!