使用 eShopOnWeb 参考应用程序的干净架构 - Entity Framework 核心性能高效查询 - 仅项目您需要的属性
Clean architecture using eShopOnWeb reference application - Entity Framework Core Performance Efficient Querying - Project only properties you need
我正在阅读 Microsoft Docs 上的清洁架构。
我还下载了 eShopOnWeb 参考应用程序。
https://github.com/dotnet-architecture/eShopOnWeb
如下图所示,参考实现视图模型保存在 Web
项目中,Dtos 保存在 PublicApi
项目中。
查看实体如何转换为视图模型和 Dto,如下所示:
var items = await _catalogBrandRepository.ListAsync();
response.CatalogBrands.AddRange(items.Select(_mapper.Map<CatalogBrandDto>));
或
var orders = await _orderRepository.ListAsync(specification, cancellationToken);
return orders.Select(o => new OrderViewModel
为_catalogBrandRepository
和_orderRepository
设置IRepository
的代码。
builder.Services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
builder.Services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));
或:
services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
在需要性能并且我只想投影我需要的属性之前,这非常有效。
鉴于设置我不能不select直接给一个Dto给定引用会出错:
public class EfRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
private readonly CatalogContext _dbContext;
public EfRepository(CatalogContext dbContext) : base(dbContext)
{
_dbContext = dbContext;
}
public List<OrderViewModel> GetAllOrderViewModels()
{
//Does not work
return _dbContext.Orders.Select(o => new OrderViewModel
{
OrderDate = o.OrderDate,
OrderNumber = o.Id,
ShippingAddress = o.ShipToAddress,
Total = o.Total()
}).ToList();
}
}
我当然可以 return 匿名类型是动态的,但这不是好的体系结构。
public List<dynamic> GetAllOrderViewModels()
{
return _dbContext.Orders.Select(o => new
{
OrderDate = o.OrderDate,
OrderNumber = o.Id,
ShippingAddress = o.ShipToAddress,
Total = o.Total()
}).ToList<dynamic>();
}
将特定 Dto 添加到 ApplicationCore
、Infrastructure
的正确方法是正确的还是我遗漏了什么?
我发现最相似的是 BasketQueryService
,但它只有 return 一个 int
。
public class BasketQueryService : IBasketQueryService
{
private readonly CatalogContext _dbContext;
public BasketQueryService(CatalogContext dbContext)
{
_dbContext = dbContext;
}
/// <summary>
/// This method performs the sum on the database rather than in memory
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public async Task<int> CountTotalBasketItems(string username)
{
var totalItems = await _dbContext.Baskets
.Where(basket => basket.BuyerId == username)
.SelectMany(item => item.Items)
.SumAsync(sum => sum.Quantity);
return totalItems;
}
}
鉴于问题是关于 Clean architecture
我认为可以被问到。
Application Core
The Application Core holds the business model, which
includes entities, services, and interfaces. These interfaces include
abstractions for operations that will be performed using
Infrastructure, such as data access, file system access, network
calls, etc. Sometimes services or interfaces defined at this layer
will need to work with non-entity types that have no dependencies on
UI or Infrastructure. These can be defined as simple Data Transfer
Objects (DTOs).
鉴于此文档,我创建了一个 OrderDto
并将其放置在 ApplicationCore
-> Dto
.
namespace Microsoft.eShopWeb.ApplicationCore.Dto;
public class OrderDto
{
private const string DEFAULT_STATUS = "Pending";
public int OrderNumber { get; set; }
public DateTimeOffset OrderDate { get; set; }
public decimal Total { get; set; }
public string Status => DEFAULT_STATUS;
public Address ShippingAddress { get; set; }
}
EfRepository
中的示例,尽管基于 BasketQueryService
的 OrderQueryService
会更好:
public List<OrderDto> GetAllOrderDtos()
{
return _dbContext.Orders.Select(o => new OrderDto
{
OrderDate = o.OrderDate,
OrderNumber = o.Id,
ShippingAddress = o.ShipToAddress,
Total = o.Total()
}).ToList();
}
我正在阅读 Microsoft Docs 上的清洁架构。
我还下载了 eShopOnWeb 参考应用程序。
https://github.com/dotnet-architecture/eShopOnWeb
如下图所示,参考实现视图模型保存在 Web
项目中,Dtos 保存在 PublicApi
项目中。
查看实体如何转换为视图模型和 Dto,如下所示:
var items = await _catalogBrandRepository.ListAsync();
response.CatalogBrands.AddRange(items.Select(_mapper.Map<CatalogBrandDto>));
或
var orders = await _orderRepository.ListAsync(specification, cancellationToken);
return orders.Select(o => new OrderViewModel
为_catalogBrandRepository
和_orderRepository
设置IRepository
的代码。
builder.Services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
builder.Services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));
或:
services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
在需要性能并且我只想投影我需要的属性之前,这非常有效。
鉴于设置我不能不select直接给一个Dto给定引用会出错:
public class EfRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
private readonly CatalogContext _dbContext;
public EfRepository(CatalogContext dbContext) : base(dbContext)
{
_dbContext = dbContext;
}
public List<OrderViewModel> GetAllOrderViewModels()
{
//Does not work
return _dbContext.Orders.Select(o => new OrderViewModel
{
OrderDate = o.OrderDate,
OrderNumber = o.Id,
ShippingAddress = o.ShipToAddress,
Total = o.Total()
}).ToList();
}
}
我当然可以 return 匿名类型是动态的,但这不是好的体系结构。
public List<dynamic> GetAllOrderViewModels()
{
return _dbContext.Orders.Select(o => new
{
OrderDate = o.OrderDate,
OrderNumber = o.Id,
ShippingAddress = o.ShipToAddress,
Total = o.Total()
}).ToList<dynamic>();
}
将特定 Dto 添加到 ApplicationCore
、Infrastructure
的正确方法是正确的还是我遗漏了什么?
我发现最相似的是 BasketQueryService
,但它只有 return 一个 int
。
public class BasketQueryService : IBasketQueryService
{
private readonly CatalogContext _dbContext;
public BasketQueryService(CatalogContext dbContext)
{
_dbContext = dbContext;
}
/// <summary>
/// This method performs the sum on the database rather than in memory
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public async Task<int> CountTotalBasketItems(string username)
{
var totalItems = await _dbContext.Baskets
.Where(basket => basket.BuyerId == username)
.SelectMany(item => item.Items)
.SumAsync(sum => sum.Quantity);
return totalItems;
}
}
鉴于问题是关于 Clean architecture
我认为可以被问到。
Application Core
The Application Core holds the business model, which includes entities, services, and interfaces. These interfaces include abstractions for operations that will be performed using Infrastructure, such as data access, file system access, network calls, etc. Sometimes services or interfaces defined at this layer will need to work with non-entity types that have no dependencies on UI or Infrastructure. These can be defined as simple Data Transfer Objects (DTOs).
鉴于此文档,我创建了一个 OrderDto
并将其放置在 ApplicationCore
-> Dto
.
namespace Microsoft.eShopWeb.ApplicationCore.Dto;
public class OrderDto
{
private const string DEFAULT_STATUS = "Pending";
public int OrderNumber { get; set; }
public DateTimeOffset OrderDate { get; set; }
public decimal Total { get; set; }
public string Status => DEFAULT_STATUS;
public Address ShippingAddress { get; set; }
}
EfRepository
中的示例,尽管基于 BasketQueryService
的 OrderQueryService
会更好:
public List<OrderDto> GetAllOrderDtos()
{
return _dbContext.Orders.Select(o => new OrderDto
{
OrderDate = o.OrderDate,
OrderNumber = o.Id,
ShippingAddress = o.ShipToAddress,
Total = o.Total()
}).ToList();
}