In Chameleon
, views are defined in chameleon.Views
table.
Structure of this table is as follows:
Column | Type | Description |
---|---|---|
name
|
nvarchar(200)
|
view name. It should be a value by which the view can be uniquely accessed. |
content
|
nvarchar(max)
|
content of the view. |
compiledContent
|
nvarchar(max)
|
compiled content of the view. It is used as a cache in order to prevent unnecessary compile and enhance performance. |
isCompiled
|
bit
|
It shows whether the view is already compiled or not. |
When defining a view, the only required thing is its content and giving it a unique name. compiledContent
and isCompiled
are system fields used by chameleon.RenderView
when rendering/executing the view. This is explained later.
Views are needed to be compiled in order to be rendered. This is done by View Engines. Chameleon
uses a view engine named Gila (pronounced Hila) by default. It is also possible to create custom view engines and set them as default.
View engines are defined as UDF function. The name of Gila view-engine function is chameleon.GilaCompile
. Here is its signature.
CREATE or ALTER FUNCTION [chm].[GilaCompile]
(
@context_id INT NULL,
@viewName NVARCHAR (200) NULL,
@viewContent NVARCHAR (MAX) NULL
)
RETURNS NVARCHAR (MAX)
@context_id
: unique context id of current web request. It enables developer to access details of current request or response (url, headers, cookies, route values, etc.). If we don't want to access any context tables, e.g. we are calling the UDF manually, we can pass an arbitrary value like 0.@viewName
: unique name of the view. It is used to distinguish view sections when templates are used. If there is only one view, we can pass null
or an empty string.@viewContent
: content of the view.Example:
declare @view nvarchar(max)
declare @compiledView nvarchar(max)
set @view = N'
<%
declare @name varchar(30)
set @name = ''Chameleon!''
%>
<h1>Welcome to <%=@name%></h1>
'
set @compiledView = chm.GilaCompile(0, '', @view)
The above code, generates the following T-SQL code for the view.
set @__result = ''
declare @name varchar(30)
set @name = 'Chameleon!'
set @__result = @__result + N'
<h1>Welcome to '
set @__result = @__result + chm.HtmlEncode(@name)
set @__result = @__result + N'</h1>
'
As it is seen, the generated code is set to @compiledView
variable. So, it can be easily executed using sp_executesql
. This is explained in next section.
After compiling a view, its compiled content can be executed using sp_executesql
system stored procedure. When Gila view engine compiles a view, it uses an output variable named @__result
in the compiled code to store the generated content. Thus, when calling sp_executesdql
, we should define such parameter for the compiled code. The variable we specify for that will hold the resulting content after sp_executesql
is finished executing.
declare @result nvarchar(max)
exec sp_executesql @compiledView, N'@__result nvarchar(max) out', @__result = @result out
print @result
Here is the final output of executing the compiled view:
<h1>Welcome to Chameleon!</h1>
There could also be a @model
input parameter for a view by which we can pass some data to a view. Examples of parametric views is described in Gila's documentation.
In Chameleon
, rendering a view is performed by a stored procedure named chameleon.RenderView
.
CREATE or ALTER PROCEDURE [chameleon].[RenderView]
(
@context_id int,
@name nvarchar(100),
@model nvarchar(max),
@result nvarchar(max) out
)
@context_id
: context_id of the current web request.@name
: view name in chameleon.Views
table.@model
: custom model that should be passed to view when it is executed.@result
: final output
chameleon.RenderView
checks first if the view is already compiled or not using the isCompiled
field. If it is not compiled, it tries to compile the view using the view-engine that is set for Chameleon
framework (Gila view-engine by default). If compilation is successful, it then stores compiled content into compiledContent
field for the given view, so that it does not need to re-compile the view next time. Next, it executes the compiled content using sp_executesql
as it was described in previous section.
By default, isCompiled
is 0
(false
) for any view that is inserted into chameleon.Views
table. After chameleon.RenderView
renders (and thus compiles) a view, it sets this column to 1
(true
) for the view. if the view content is updated, the isCompiled
flag is set back to 0
again, so that in next RenderView
invocation, correct output is returned back to the user not the old stale content. This is done by an update
trigger named [chameleon].[Views_Update]
that clears isCompiled
field for updated records whenever content of any record is changed.
-- After execution of the following UPDATE command, [chameleon].[Views_Update] is triggered
-- and [isCompiled] will be set to 0 for 'my-view' record.
update chameleon.Views set [content] = N'...' where [name] = 'my-view'
It is also possible to manually reset isCompiled
so that the view is compiled explicitly on next render.
update chameleon.Views set [isCompiled] = 0 where [name] = 'my-view'
All view engines should be defined as UDF functions in order to be invocable by chameleon.RenderView
. Name of all view-engine UDF functions should end in Compile
and their signature should follow the following signature.
CREATE or ALTER FUNCTION MyViewEngineCompile
(
@context_id INT NULL,
@viewName NVARCHAR (200) NULL,
@viewContent NVARCHAR (MAX) NULL
)
RETURNS NVARCHAR (MAX)
As it is seen, view-engine compile function should have three parameters @context_id
, viewName
and viewContext
of int
, nvarchar(200)
and nvarchar(max)
data type respectively and should return nvarchar(max)
. The function could be defined in any schema. It is developer's choice. GilaCompiled
is defined in chm
schema.
A view-engine compile function could be implemented as a pure T-SQL UDF or a SQL-CLR UDF. Gila
itself is implemented as a SQL-CLR UDF and is added to database when Chameleon
framework is installed.
chm.GilaCompile
function internally uses GilaViewEngine
class in Chameleon.Core library. Definition of Chamelelon
view-engines is described in Chameleon.Core
's IChameleonViewEngine
interface.
It is not necessary that a SQL-CLR view-engine should implement IChameleonViewEngine
interface. The only thing that is necessary is that the resulting function follows the signature described in a few paragraphs above.