使 Laravel 模型使用复杂查询作为表

Posted

技术标签:

【中文标题】使 Laravel 模型使用复杂查询作为表【英文标题】:Making a Laravel Model use complex query as table 【发布时间】:2016-07-01 22:28:34 【问题描述】:

我正在开发一个与 ERP 生产数据库交互的 Web 应用程序,并且在将数据传递给以不同方式修改它们的控制器和视图之前,通过具有许多连接和别名的复杂 SQL 查询来检索数据。

例如,结果可能是一组产品,其中包含每次购买的所有相关信息,例如型号、序列号、客户等,而在较小规模的应用程序中,这些肯定都存储在同一个表。

但是,因为我从一个非常复杂的 ERP 解决方案中提取这些细节,所以这些详细信息来自许多不同的表,但我想在我的模型中将其视为一个表。

有什么办法可以让我像往常一样使用 Eloquent 吗?像 Product::all() 这样的东西不起作用,虽然我可以调用像 Product::getWhere($serial) 这样的自定义方法,但我宁愿以 Eloquent 方式执行此操作,因为它更容易并且使分页更易于使用。

以下是我的查询的样子:

SELECT
[PSerials].[ElementID] AS [ProductElementID],
[PSerials].[SerialNumber] AS [SerialNumber],
[PSerials].[SNStatus] as [ProductStatus],
[PSerials].[JobID] AS [JobID],
[Element].[Desc] AS [Description],
[PSerials_UD].[Prog] AS [ProgramNum],
[PSerials_UD].[Elec] AS [ElecPrint],
[PSerials_UD].[SinglePHVolt_c] AS [SinglePHVolt],
[PSerials_UD].[SinglePHAmp_c] AS [SinglePHAmp],
[PSerials_UD].[ThreePHVolt_c] AS [ThreePHVolt],
[PSerials_UD].[ThreePHAmp_c] AS [ThreePHAmp],
[PSerials_UD].[Notes_c] AS [Notes],
[PSerials_UD].[WarrantyExpDate_c] AS [WarrantyExpDate],
[QuoteDtl].[QuoteNum] AS [QuoteNum],
[QuoteDtl].[QuoteComment] AS [QuoteComment],
[OrderDtl].[RequestDate] AS [ShipDate],
[Customer].[CustID] AS [CustomerID],
[Customer].[Name] AS [CustomerName],
[Customer1].[CustID] AS [ShipToCustomerID],
[Customer1].[Name] AS [ShipToCustomerName]
FROM Erp.PSerials AS PSerials
INNER JOIN Erp.Element AS Element ON
PSerials.Company = Element.Company AND PSerials.ElementID = Element.ElementID
AND (Element.ProdCode = 'MACH' AND Element.ClassID = 'MAC')
INNER JOIN Erp.PSerials_UD AS PSerials_UD ON
PSerials_UD.ForeignSysRowID = PSerials.SysRowID
LEFT OUTER JOIN Erp.PProd AS PProd ON PProd.JobID = PSerials.JobID
LEFT OUTER JOIN Erp.OrderDtl AS OrderDtl ON PProd.Company = OrderDtl.Company
AND PProd.OrderNum = OrderDtl.OrderNum AND PProd.OrderLine = OrderDtl.OrderLine
LEFT OUTER JOIN Erp.QuoteDtl AS QuoteDtl ON OrderDtl.QuoteNum = QuoteDtl.QuoteNum
AND OrderDtl.QuoteLine = QuoteDtl.QuoteLine
LEFT OUTER JOIN Erp.Customer AS Customer ON  OrderDtl.Company = Customer.Company
AND OrderDtl.CustNum = Customer.CustNum
LEFT OUTER JOIN Erp.Customer AS Customer1 ON PSerials.Company = Customer1.Company
AND PSerials.ShipToCustNum = Customer1.CustNum

我将它放在我的 Product 模型上的一个静态变量中,然后有自定义函数,可以根据需要简单地将 SQL 查询添加到最后,但这并不优雅,使用起来也不有趣,这是我如何使用这些查询的示例:

public static function getWhere($serial)

    $query = DB::select(DB::raw(Self::$baseQuery));
    $collection = new \Illuminate\Support\Collection($query);

    $product = $collection->where("SerialNumber", $serial)->first();

    return $product;

有没有人可以让我的模型简单地将这样的查询视为一个简单的表,或者是否有其他方法可以做到这一点?

更新

感谢 Zamrony P. Juhara 在下面的建议,我能够成功创建 SQL 视图并告诉我的 Products 模型引用就像一张表:

class Product extends Model

    protected $table = 'dbo.ProductInfo';

现在Product::all() 可以正常工作了。

关于 Peh 指出的限制,这个应用程序纯粹是为了查看 ERP 软件中存在的数据,不需要更新或删除任何记录,所以在这种情况下 SQL 视图是绝对完美的。

【问题讨论】:

【参考方案1】:

您可以将 SQL 命令转换为 VIEW (CREATE VIEW),然后像模型中的普通表一样使用它。

【讨论】:

需要说明的是,在更新/插入数据时可以限制视图。要使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。还有某些其他构造使视图不可更新。欲了解更多信息,请参阅here。 所以 SQL 视图是在服务器端创建的,有点像代理表?我不确定我是否能够这样做,因为它可能会影响我们使用我们使用的 ERP 软件包的保修。

以上是关于使 Laravel 模型使用复杂查询作为表的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 复杂查询

复杂的 SQL / Laravel Eloquent 查询

JPA 2 向表添加引用约束使标准查询与延迟获取复杂化,需要建议

Laravel 5 中使用查询生成器的复杂查询

使用 Laravel Query Builder 进行复杂的 MySQL 内连接查询

使用链式方法的 Laravel 复杂范围查询