复杂 Join/Query 与 OrmLite ServiceStack

Complex Join/Query with OrmLite ServiceStack

我在将 EF linq 示例转换为 OrmLite 时遇到问题。我已经确定了大部分查询,但一些深度连接或子查询正在解决一些问题。

这是我的 EF 查询:

var q = from orderProduct in orderProducts
        join order in _erpContext.Orders.Include(x => x.BillingAddress.Country) on orderProduct.OrderId equals order.Id
        join product in _erpContext.Products.Include(x => x.ProductCategories).Include(x => x.ProductManufacturers) on orderProduct.ProductId equals product.Id
        where (storeId == 0 || storeId == order.StoreId) &&
            (!startDate.HasValue || startDate.Value <= order.DateCreated) &&
            (!endDate.HasValue || endDate.Value >= order.DateCreated) &&
            (!orderStatusId.HasValue || orderStatusId == (int)order.OrderStatus) &&
            (!orderTypeId.HasValue || orderTypeId == (int)order.OrderType) &&
            (!paymentStatusId.HasValue || paymentStatusId == (int)order.PaymentStatus) &&
            (!shippingStatusId.HasValue || shippingStatusId == (int)order.ShippingStatus) &&
            (!order.Deleted) &&
            (!product.Deleted) &&
            (categoryId == 0 || product.ProductCategories.Count(pc => pc.CategoryId == categoryId) > 0) &&
            (manufacturerId == 0 || product.ProductManufacturers.Count(pm => pm.ManufacturerId == manufacturerId) > 0) &&
            (billingCountryId == 0 || order.BillingAddress.CountryId == billingCountryId);

如您所见,我在连接中使用了 Include() 函数。那是我卡住的部分。

这是我的 OrmLite 查询:

var q = _erpDbConnection.From<OrderProduct>()
.Join<Order>((x, y) => x.OrderId == y.Id)
.Join<Product>((x, y) => x.ProductId == y.Id)    
.Where<OrderProduct>(x => x.ProductId != null && !x.Order.ContainsFreeMaterial && !x.Order.IsFitSizeOrder && x.Order.OrderType != OrderType.Stock)
.And<Order, Product>((o, p) => !o.Deleted && !p.Deleted);

if (storeId > 0)
{
    q = q.And<Order>(x => x.StoreId == storeId);
}

if (billingCountryId > 0)
{
    q = q.And<Order>(x => x.BillingAddress.CountryId == billingCountryId);
}

if (startDate.HasValue)
{
    q = q.And<Order>(x => x.DateCreated <= startDate);
}

if (endDate.HasValue)
{
    q = q.And<Order>(x => x.DateCreated >= endDate);
}

if (orderStatusId.HasValue)
{
    q = q.And<Order>(x => (int) x.OrderStatus == orderStatusId);
}

if (orderTypeId.HasValue)
{
    q = q.And<Order>(x => (int)x.OrderType == orderTypeId);
}

if (paymentStatusId.HasValue)
{
    q = q.And<Order>(x => (int)x.PaymentStatus == paymentStatusId);
}

if (shippingStatusId.HasValue)
{
    q = q.And<Order>(x => (int)x.ShippingStatus == shippingStatusId);
}

if (categoryId > 0)
{
    q = q.And<Product>(x => x.ProductCategories.Any(y => y.CategoryId == categoryId));
}

if (manufacturerId > 0)
{
    q = q.And<Product>(product => product.ProductManufacturers.Any(y => y.ManufacturerId == manufacturerId));
}

var filteredOrderProducts = _erpDbConnection.Select<OrderProduct>(q);

OrmLite 提供了类型化的 1:1 API 映射到正常 SQL,因此转换生成的 SQL 通常比 EF 查询更容易,后者通常不清楚查询是什么正在生成。

默认情况下 OrmLite SELECT 的来源 table 在这种情况下是 OrderProduct:

var q = _erpDbConnection.From<OrderProduct>()

执行查询时返回的内容,即:

List<OrderProduct> results = db.Select(q);

要包含相关数据,您需要在源 OrderProduct 上定义 POCO References,然后可以使用 Load* API 加载(深度 1 级) ,例如:

List<OrderProduct> results = db.LoadSelect(q);

您还可以使用 SelectMulti 一次 select 多个 table,例如:

var results = db.SelectMulti<OrderProduct, Order, Product>(q);

foreach (var tuple in results)
{
    OrderProduct orderProduct = tuple.Item1;
    Order order = tuple.Item2;
    Product product = tuple.Item3;
}

对于任何其他自定义结果,您需要指定包含您想要 select 的结果的自定义 Select,例如:

q.Select<OrderProduct,Order,Product>((op,o,p) => 
    new {
        op,     // all fields from OrderProduct table
        o.Id,
        p.Name,
        etc...
    });

但是您需要在包含与上述查询匹配的 public 属性的自定义架构中访问自定义结果集,例如:

var results = db.Select<OrderProductView>(q);

或使用 OrmLite's dynamic result set APIs 之一。


另请注意,您不能在 OrmLite 中进行嵌套查询,例如:

.Where<OrderProduct>(x => x.ProductId != null 
    && !x.Order.ContainsFreeMaterial 
    && !x.Order.IsFitSizeOrder 
    && x.Order.OrderType != OrderType.Stock)

您需要查询 table 上的字段(就像您在正常 SQL 中所做的那样),您也可以在相同条件下查询多个 table:

.Where<OrderProduct,Order>((op,o) => ...);