Set up enumerated properties
Several values the template needs from the user have only a few valid choices. For example, EXECUTE AS accepts only CALLER, OWNER or SELF; anything else is a T-SQL error. Instead of free-form input (and the risk of an invalid value), offer a list of just the valid choices with an enumerated property.
Add an enumeration
To set up an enumerated property, you define a type that allows only the values you want: an enumeration.
-
Move to the end of the template and start typing
<script. The Template Editor offers to complete a script block. -
Press Tab, or click the suggestion, to insert the script block with its closing tag.
-
Inside the script block, define the enumeration:
<script runat="template"> Public Enum ExecuteAsEnum CALLER OWNER SELF End Enum </script>
Declare the property
Add a Property directive that uses the new type:
<%@ Property Name="ExecuteAs" Type="ExecuteAsEnum" Category="Options" Default="CALLER" Description="The security context the procedure runs in." %>
Writing an enumeration value to the output writes its name, so <%= ExecuteAs %> writes CALLER, OWNER or SELF: exactly the T-SQL keyword. The same goes for the FOR JSON mode, with an enumeration of PATH and AUTO.
Translate values that aren't valid names
Isolation levels are different: READ COMMITTED has a space, and an enumeration value can't. Name the values with underscores instead, and add a helper function inside the script block that returns the T-SQL for each one:
Public Enum IsolationLevelEnum
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SNAPSHOT
SERIALIZABLE
End Enum
Public Function GetIsolationLevel(ByVal Level As IsolationLevelEnum) As String
Select Case Level
Case IsolationLevelEnum.READ_UNCOMMITTED
Return "READ UNCOMMITTED"
Case IsolationLevelEnum.REPEATABLE_READ
Return "REPEATABLE READ"
Case IsolationLevelEnum.SNAPSHOT
Return "SNAPSHOT"
Case IsolationLevelEnum.SERIALIZABLE
Return "SERIALIZABLE"
Case Else
Return "READ COMMITTED"
End Select
End Function
Now <%= GetIsolationLevel(IsolationLevel) %> writes the user's choice anywhere in the template.
The template so far
With the three enumerations, their properties and the helper function, the template looks like this:
<%@ CodeTemplate Language="VB" TargetLanguage="T-SQL" Description="Creates a stored procedure that returns a table's rows as JSON." %>
<%@ Property Name="ExecuteAs" Type="ExecuteAsEnum" Category="Options" Default="CALLER" Description="The security context the procedure runs in." %>
<%@ Property Name="IsolationLevel" Type="IsolationLevelEnum" Category="Options" Default="READ_COMMITTED" Description="The transaction isolation level for the query." %>
<%@ Property Name="JsonMode" Type="JsonModeEnum" Category="Options" Default="PATH" Description="How FOR JSON shapes the output." %>
CREATE OR ALTER PROCEDURE Person.GetAddressTypeJson
WITH EXECUTE AS <%= ExecuteAs %>
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL <%= GetIsolationLevel(IsolationLevel) %>;
SELECT
[AddressTypeID],
[Name],
[rowguid],
[ModifiedDate]
FROM
[Person].[AddressType]
FOR JSON <%= JsonMode %>, ROOT('AddressType');
END
GO
<script runat="template">
Public Enum ExecuteAsEnum
CALLER
OWNER
SELF
End Enum
Public Enum IsolationLevelEnum
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SNAPSHOT
SERIALIZABLE
End Enum
Public Enum JsonModeEnum
PATH
AUTO
End Enum
Public Function GetIsolationLevel(ByVal Level As IsolationLevelEnum) As String
Select Case Level
Case IsolationLevelEnum.READ_UNCOMMITTED
Return "READ UNCOMMITTED"
Case IsolationLevelEnum.REPEATABLE_READ
Return "REPEATABLE READ"
Case IsolationLevelEnum.SNAPSHOT
Return "SNAPSHOT"
Case IsolationLevelEnum.SERIALIZABLE
Return "SERIALIZABLE"
Case Else
Return "READ COMMITTED"
End Select
End Function
</script>
Save the template. One thing is still missing: a connection to the database. You add that next.
Next: Set up a SQL property