我正在努力使自己了解如何在应用程序中实现dapper。我有n层mvc应用程序,并且对EF有一定的经验。即使我认为EF很好,我也没有通过学习曲线来使它顺畅地进行并且不与性能作斗争。在新项目中,我们决定尝试使用dapper,主要是为了控制sql并希望获得良好的性能。
背景
我用这些图层创建了一个分层的应用程序(核心)
网页-mvc
服务-业务层以处理业务逻辑
数据-用于访问ms sql服务器的数据层
我继续着手并开始在数据层中实现UnitOfWork和通用存储库。
数据库中的正常结构应为
Order
ref to User
ref to Address
OrderLine
ref to Product
在许多情况下,我想检索所有系列和产品的多个订单。
所以我要做的是像在EF中那样在实体模型上具有导航属性,并使用多查询器将它们填充到dapper中,或者将结果拆分为不同的实体并将其映射到图形。
问题
我遇到的问题是插入时。我有一个sqlextension将属性映射到表列。但是默认情况下,导航也会被映射。我意识到我可以用属性修饰并在映射上读取它们,但是当我在Google上搜索时,我意识到也许应该删除UnitOfWork模式以及存储库,使数据层“超薄”并公开连接。 然后,服务层将使用正确的sql调用Dapper,类似于我今天要执行的操作,但是使用存储库。
我还将删除导航属性,并自行获取每个实体,并将其合并到ViewModel中。
我的问题是,如果我们使用上面的订单表,则必须执行以下操作才能获得完整列表(通常是分页显示,也删除了用户名/地址)
var listModel = new OrderListViewModel();
var orders = orderService.GetAll();
foreach(var order in orders) {
var orderModel = new OrderViewModel(); // also map fields
var orderLines = orderService.GetOrderLinesForOrder(order.OrderId);
foreach(var orderline in orderLines) {
var orderLineModel = new OrderLineViewModel(); // also map fields
var product = productService.GetProduct(orderline.ProductId);
orderLineModel.Product = new ProductViewModel(); // also map fields
orderModel.OrderLines(orderLineModel);
}
listModel.Orders.Add(orderModel);
}
这将生成很多查询(几乎类似于EF延迟加载)。所以我可以做一个映射事
var orders = orderService.GetAll();
var orderLines = orderService.GetOrderLinesForOrders(orders.Select(o => o.OrderId).ToArray() ); // get all orderlines for all orders
var products = productService.GetProductsForOrderLines(orderLines.Select(p => p.OrderLineId).ToArray() ); // get all products for all orderlines
foreach(var order in orders) {
var orderModel = new OrderViewModel(); // also map fields
var orderLines = orderLines.Where( o => o.OrderId == order.OrderId );
foreach(var orderline in orderLines) {
var orderLineModel = new OrderLineViewModel(); // also map fields
var product = products.First(p => p.ProductId == orderline.ProductId);
orderLineModel.Product = new ProductViewModel(); // also map fields
orderModel.OrderLines(orderLineModel);
}
listModel.Orders.Add(orderModel);
}
这将产生较少的SQL查询,并且我认为性能最佳。我知道参数超过2100(?)可能会出现问题,但是我认为这不会成为问题。 问题在于许多out表的状态不同,并且与其他表的关系也很多。我将不得不一直进行很多此类查询。
当我第一次进行存储库和导航时,我会这样做
repo.Get<Order, OrderLines, Product, Order>(sqlThatWouldJoinAllTables);
// split and map the structure into order Entity and just return that
这样,我可以调用orderService.GetAll()并检索订单,订单行和产品图。
我不知道哪种解决方案是“最佳实践”。我试图找到一个使用图层和dapper的好的开源项目来获得一些实际的用法,但是没有成功。 删除导航属性的方法还消除了服务层的某些用途,因为我以某种方式将一些业务逻辑移至mvc控制器。
我找不到很好的练习方法,请提出建议。
答案 0 :(得分:0)
如果您正在使用的RDBMS支持JSON,我建议将您需要插入的所有内容包装到JSON中,然后仅通过一次调用将其发送到存储过程。可以使用相同的技术通过一个调用返回相关对象的图形。工作单元(实际上是事务)将在存储过程本身中得到照顾,这也是处理对数据IMHO进行操作的事务的正确位置。
这极大地减少了往返次数,但以数据库上使用更多的CPU为代价。除非您期望数量庞大(每秒每秒并发几千个并发查询,否则通常不是问题)。
我在这里对此进行了广泛的撰写:
https://medium.com/dapper-net/one-to-many-mapping-with-dapper-55ae6a65cfd4
更具体地说,“复杂的自定义处理”示例准确显示了我提到的内容。