Stored procedures 开发存储过程时如何使用依赖项注入?

Stored procedures 开发存储过程时如何使用依赖项注入?,stored-procedures,dependency-injection,Stored Procedures,Dependency Injection,在数据库中,存储过程通常用于处理业务逻辑。(关于逻辑应该在哪里存在争议,但这不是本文的主题) 当越来越多的SP被写入时,系统变得非常复杂。我认为主要原因是依赖性(SP1依赖于SP2,SP2依赖于SP3…) 在OO世界中,有依赖注入模式和许多IoC容器(如Spring)来解决依赖问题。 在SP世界中,这种模式可以应用吗?怎样任何工具?依赖项注入在支持多态性的环境中都是有意义的:您有一个可以有多种实现之一的接口,您可以将正确实现的发现转移到某个框架中 在SQL中,存储过程接口和它的实现之间没有距离—

在数据库中,存储过程通常用于处理业务逻辑。(关于逻辑应该在哪里存在争议,但这不是本文的主题) 当越来越多的SP被写入时,系统变得非常复杂。我认为主要原因是依赖性(SP1依赖于SP2,SP2依赖于SP3…) 在OO世界中,有依赖注入模式和许多IoC容器(如Spring)来解决依赖问题。
在SP世界中,这种模式可以应用吗?怎样任何工具?

依赖项注入在支持多态性的环境中都是有意义的:您有一个可以有多种实现之一的接口,您可以将正确实现的发现转移到某个框架中

在SQL中,存储过程接口和它的实现之间没有距离——您用过程定义接口。当您实际将多个过程定义为在一个公共签名中可以互换时,很难想象会发生什么情况

实际上,对于依赖项注入,您还需要一些键来告诉系统您想要注入的是什么。在OOP语言中,接口通常是一个键。但您可能不希望SP签名作为密钥。若你们按名称查找这个过程,那个么它和直接执行它有什么不同呢


OOP之所以存在,为什么它是管理复杂性的一种流行方式,这是有原因的。依赖项注入建立在其核心概念之上,似乎不太适用于过程环境。

依赖项注入在支持多态性的环境中最有意义:您有一个接口,可以有许多实现之一,您可以将正确实现的发现转移到某个框架上

在SQL中,存储过程接口和它的实现之间没有距离——您用过程定义接口。当您实际将多个过程定义为在一个公共签名中可以互换时,很难想象会发生什么情况

实际上,对于依赖项注入,您还需要一些键来告诉系统您想要注入的是什么。在OOP语言中,接口通常是一个键。但您可能不希望SP签名作为密钥。若你们按名称查找这个过程,那个么它和直接执行它有什么不同呢


OOP之所以存在,为什么它是管理复杂性的一种流行方式,这是有原因的。依赖项注入建立在其核心概念之上,似乎不太适用于过程环境。

尽管不推荐使用。有一种方法可以在SQL环境中(使用存储过程、函数、视图甚至表)使用依赖项注入。它涉及大量的动态SQL、触发器,过一段时间就会变得非常混乱。但是,为了回答这个问题,下面是:

首先,您必须决定要注入什么样的依赖项,以及如何访问它。比方说,在本例中,它是一个公司ID,您希望根据公司执行不同的对象,同时在更高级别的过程中保持不可知状态,并遵循D.R.Y(不要重复您自己)

因此,您需要一种存储此公司ID的方法,无论您在何处以及传入的内容如何,都可以随时检索。您不希望总是必须将公司ID传递给SQL对象,因此可以使用上下文信息。这是一个通过线程保持不变的值,并且对于该线程是唯一的

SET @Context = CAST(15 AS VARBINARY(128))
SET CONTEXT_INFO @Context;
现在,您可以像这样访问上下文:

SELECT @Context = CONTEXT_INFO();
SET @CompanyID = CAST(@Context AS INT)
到目前为止你和我在一起吗? 这就是它开始变得非常混乱的地方。
用公司特定对象的名称为自己创建一个表

CREATE TABLE CompanyObjectRegistry (ObjectSchema VARCHAR(100), ObjectName VARCHAR(100), CompanyID)
在此处存储您的对象:

INSERT CompanyObjectRegistry
VALUES ('CompanyFifteen', 'DoSomethingCool', 15),
     ('CompanyTwelve', 'DoSomethingCool', 12);
然后创建顶级过程:

CREATE PROCEDURE DoSomethingCool (@Data VARCHAR(10), @Param2 INT) 
AS 
DECLARE @CompanyID INT = CAST(CONTEXT_INFO() AS INT),
    @SQL NVARCHAR(MAX) = '
    EXEC [SCHEMA].DoSomethingCool ''' + @Data + ''', ' 
      + CAST(Param2 AS VARCHAR(10)) + ';'
SET
SELECT @SQL = REPLACE(@SQL, '[SCHEMA]', ObjectSchema)
FROM CompanyObjectRegistry
WHERE CompanyID = @CompanyID

EXEC(@SQL)
由于DSQL以及无法编译的事实,这会产生很小的开销。您可以通过使用“生成”过程来消除一些开销,该过程自动从CompanyObjectRegistry的内容生成此“基本”过程,并使用IF语句

如果需要,可以将触发器添加到CompanyObjectRegistry,并在编辑/添加一个基础对象时生成基础对象。对此,您将使用DDL触发器

以下是如何为表执行此操作:

DECLARE @TableName VARCHAR(100) = 'DoSomethingCool';
SET @SQL = 'CREATE VIEW ' + @TableName + ' AS '
+ (SELECT '
            SELECT * FROM ' + ObjectSchema + '.' + ObjectName + ' 
            WHERE ' + CAST(CompanyID AS VARCHAR(10)) + ' = @CompanyID
            UNION ALL ' -- You would have to remove the last 10 characters from the result
    FROM CompanyObjectRegistry
    WHERE ObjectName = @TableName
    FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)')

EXEC (@SQL)
视图可以以相同的方式注入,只需从每个视图中选择*即可。 函数很难实现,因为上述两种方法都无法实现。您必须使用函数的标题并生成主体


这需要很多时间。所以如果你有选择的话。。。不要这样做。

尽管不建议这样做。有一种方法可以在SQL环境中(使用存储过程、函数、视图甚至表)使用依赖项注入。它涉及大量的动态SQL、触发器,过一段时间就会变得非常混乱。但是,为了回答这个问题,下面是:

首先,您必须决定要注入什么样的依赖项,以及如何访问它。比方说,在本例中,它是一个公司ID,您希望根据公司执行不同的对象,同时在更高级别的过程中保持不可知状态,并遵循D.R.Y(不要重复您自己)

因此,您需要一种存储此公司ID的方法,无论您在何处以及传入的内容如何,都可以随时检索。您不希望总是必须将公司ID传递给SQL对象,因此可以使用上下文信息。这是一个通过线程保持不变的值,并且对于该线程是唯一的

SET @Context = CAST(15 AS VARBINARY(128))
SET CONTEXT_INFO @Context;
现在,您可以像这样访问上下文:

SELECT @Context = CONTEXT_INFO();
SET @CompanyID = CAST(@Context AS INT)
到目前为止你和我在一起吗? 这就是它开始变得非常混乱的地方。
用公司特定对象的名称为自己创建一个表

CREATE TABLE CompanyObjectRegistry (ObjectSchema VARCHAR(100), ObjectName VARCHAR(100), CompanyID)
在此处存储您的对象:

INSERT CompanyObjectRegistry
VALUES ('CompanyFifteen', 'DoSomethingCool', 15),
     ('CompanyTwelve', 'DoSomethingCool', 12);
然后创建顶级过程:

CREATE PROCEDURE DoSomethingCool (@Data VARCHAR(10), @Param2 INT) 
AS 
DECLARE @CompanyID INT = CAST(CONTEXT_INFO() AS INT),
    @SQL NVARCHAR(MAX) = '
    EXEC [SCHEMA].DoSomethingCool ''' + @Data + ''', ' 
      + CAST(Param2 AS VARCHAR(10)) + ';'
SET
SELECT @SQL = REPLACE(@SQL, '[SCHEMA]', ObjectSchema)
FROM CompanyObjectRegistry
WHERE CompanyID = @CompanyID

EXEC(@SQL)
由于DSQ,这有一个小的开销