如何将具有一对多相关数据的SQL Server视图映射到ASP.NET Core 2.2中具有ICollection的ViewModel类

问题描述 投票:0回答:1

我想创建一个如下所示的视图模型,其中CustomerInfo是包含订单集合的视图模型,每个订单都包含订单明细的集合。

 public class CustomerInfo
 {
     public CustomerInfo()
     {
         OrderInfo = new HashSet<OrderInfo>();
     }

     public int Custid { get; set; }
     public string City { get; set; }
     public string Region { get; set; }

     public virtual ICollection<OrderInfo> OrderInfo { get; set; }
 }

 public class OrderInfo
 {
     public OrderInfo()
     {
         OrderDetails = new HashSet<OrdDetails>():
     }

     public int OrderId { get; set; }
     public DateTime OrderDate { get; set; }

     public ICollection<OrdDetails> OrderDetails { get; set; }
 }

 public class OrdDetails
 {
     public int Orderid { get; set; }
     public int Productid { get; set; }
     public decimal Unitprice { get; set; }
     public short Qty { get; set; }
     public decimal Discount { get; set; }

     public virtual OrderInfo Order { get; set; }
 }

SQL Server数据库包含一个视图,该视图使用联接存储来自三个相关表:customerorderorderdetails的数据。

我是否可以使用无键实体类型或DBQuery将T-SQL视图映射到CustomerInfo视图模型类?

如果可能,我宁愿不使用DBQuery,因为最新的.NET Core版本不再支持DBQuery,并且如果我们决定升级,我不希望该应用程序损坏。

asp.net-core .net-core viewmodel one-to-many sql-view
1个回答
0
投票

这不是一件容易的事。

假设有一个实体类,声明为数据库记录包含复合CustomerOrderOrdDetail关系主列,

public partial class CustomerOrderDetail_Entity : ICustomerInfo, IOrderInfo, IOrdDetails
{
    public int Custid { get; set; }
    public string City { get; set; }
    public string Region { get; set; }
    public int OrderId { get; set; }
    public DateTime OrderDate { get; set; }
    public int Orderid { get; set; }
    public int Productid { get; set; }
    public decimal Unitprice { get; set; }
    public short Qty { get; set; }
    public decimal Discount { get; set; }
}

为了使开始时变得容易和简单,请尝试创建视图并查询这三个表中的每一列,

SELECT  
  dbo.Customer.Custid, dbo.Customer.City, dbo.Customer.Region, 
  dbo.[Order].OrderId, dbo.[Order].OrderDate, 
  dbo.OrdDetail.Productid, dbo.OrdDetail.Qty, dbo.OrdDetail.Discount, dbo.OrdDetail.Unitprice
FROM  dbo.Customer LEFT OUTER JOIN
  dbo.[Order] ON dbo.Customer.Custid = dbo.[Order].Custid LEFT OUTER JOIN
  dbo.OrdDetail ON dbo.[Order].OrderId = dbo.OrdDetail.Orderid

然后,创建数据访问,ORM功能来满足您的需求,

virtual CustomerInfo GetCustomerOrderDetail(int custId, string connectionStringName = null)
{
    IEnumerable<CustomerOrderDetail_Entity> entities;
    using (var conn = DbConnectionFactory.CreateDbConnection(connectionStringName ?? DefaultConnectionName))
    {
        conn.Open();
        entities = conn.Query<CustomerOrderDetail_Entity>(@"
SELECT *
FROM uv_CustomerOrderDetails
where CustId = @CustId
", new { CustId = custId });
    }

    return entities?.ConvertTo<CustomerInfo>(); 
}

无论您的数据结构多么复杂,它都是ORM映射的东西。由于现在所有事物都在内存中,因此使用OrdDetails将它们转换或映射为OrderInfoCustomerInfolegacy for-loop, LINQ, or 3rd-party mapper package类可能并不困难。


但是,不应为一般目的而创建第一个视图,对于不经常调用的查询,例如数据分析,这是更好的选择,否则它会不断浪费大量流量来检索带有冗余列的较大数据集,例如[ C0],Customer.City,对于客户而言,它们都是相同的,对于相同的订单,它们也都是Customer.Region

[像这样,比伯爵眼镜还相对优化的视图,

[Order].OrderDate

尽管现在节省了大量数据,但CustomerOrderDetail_Entity

数据不再完全填充。相反,需要许多支持方法来使其完成。这是一个示例,我如何使用第二个视图,然后将数据集分别转换为SELECT dbo.Customer.Custid, dbo.[Order].OrderId, dbo.OrdDetail.Productid FROM dbo.Customer LEFT OUTER JOIN dbo.[Order] ON dbo.Customer.Custid = dbo.[Order].Custid LEFT OUTER JOIN dbo.OrdDetail ON dbo.[Order].OrderId = dbo.OrdDetail.Orderid CustomerInfoOrderInfo
OrdDetails

坦率地说,随着系统复杂性的增加,还有很多事情要做。除非您的系统保持如此小,我的意见是virtual CustomerInfo GetCustomerOrderDetail(int custId, string connectionStringName = null) { var customerInfo = DBHelper.CachedCustomerInfo(custId); var orders = entities ?.Where(o => o.Custid == custId) ?.GroupBy(o => o.Custid) ?.SelectMany(group => group); if (orders?.Count() > 0 != true) { return customerInfo; } customerInfo.OrderInfo = new List<OrderInfo>(); // fill orders foreach (var order in orders) { var orderId = order.OrderId; if (orderId <= 0) { continue; } var orderInfo = DBHelper.CachedOrderInfo(orderId); customerInfo.OrderInfo.Add(orderInfo); // fill order details var orderDetails = DBHelper.CachedOrderDetails(orderId); if (orderDetails?.Count() > 0 != true) { continue; } orderInfo.OrderDetails = orderDetails.LinkOrder(orderInfo).ToList(); } return customerInfo; } // query CustomerInfo by PK:CustId, and Cache CRUD virtual CustomerInfo CachedCustomerInfo(int custId); // query OrderInfo by PK:OrderId, and Cache CRUD virtual OrderInfo CachedOrderInfo(int orderId); // query OrdDetails list by FK:OrderId, and Cache CRUD virtual IEnumerable<OrdDetails> CachedOrderDetails(int orderId); // make OrdDetails.Order property link to its owner Order virtual IEnumerable<OrdDetails> LinkOrder(this IEnumerable<OrdDetails> details, OrderInfo order);

© www.soinside.com 2019 - 2024. All rights reserved.