Tip
All examples used are valid against the Microsoft Northwind Sample Database You can run the resulting SQL from the examples against Northwind in order to test and play with the SqlObjects library.
Scripts¶
Overview¶
There are two ways that you can provide ad hoc SQL scripts when necessary. You might want to involve some stored-procedure-like logic that needs to be executed in the database or you may need to compensate for something that isn’t implemented in this library. A great deal of effort has been made to accommodate that majority of use cases for a .NET SQL builder in this library but not all of the possible variations of SQL code are covered. The intention at this time is to improve the library and add missing features over time but for now, whatever is missing can be accommodated with manually crafted SQL code using the two methods below.
The
.Script()
MethodThe
.Literal()
Method
The .Script()
and .Literal()
methods essentially do the same thing, which is to output
whatever you type into them exactly as you typed it. There is no effort to transform the code
in any way (there is some whitespace formatting however - more on that below).
Script() vs. Literal()¶
The .Script()
method will do two things for you.
First is that the code you enter into the .Script()
method will be added as a child of the
root SQL object in the underlying object model. Therefore, when it is rendered, it will not be
indented if you reference it anywhere in the middle of the Fluent script. This is strictly
eye-candy! It has no impact on the validity of the SQL you type into the script. The database
engine doesn’t care how ugly your SQL code is formatted. But if you want to ensure that your code
looks optimally readable so you can have a pleasant debugging experience (which is one of the
goals of this library), then you should only use the .Script()
method at the top or the bottom
of high-level SQL code structures. For example, use it before starting a .SELECT()
query or
after a .SELECT()
query. If the SELECT is part of a UNION then only at the bottom, etc. In short,
it is just a formatting issue.
Keep in mind that the use of .Script()
is garbage in garbage out. Your mileage will vary based on the quality of your
manually-entered code.
Secondly, the .Script()
method will deal with multi-line code. You are free to indent your code
so it looks pretty in the C# source and the object built by the .Script()
method does the job of
removing excessive indentation meant for pretty C# code and replaces it with whitespace suitable for
rendering pretty SQL code.
For example, if you do this in C#:
...
// Your C# code is indented way over here because of your
// namespace, class, and method declaration so you do this:
.Script(@"
DECLARE @someVar INT
SET @someVar = 99
")
.SELECT()
.STAR()
.FROM("MyTable")
.WHERE("Id").IsEqualTo("@someVar")
...
DECLARE @someVar INT
SET @someVar = 99
SELECT
*
FROM [MyTable]
WHERE 1=1
AND [Id] = @someVar
...
.Script()
doesn’t do that. It cleans that up for you and gives you this:DECLARE @someVar INT
SET @someVar = 99
SELECT
*
FROM [MyTable]
WHERE 1=1
AND [Id] = @someVar
Now, the .Literal()
method will also do two things for you.
One is that it will respect the place that you put it. Wherever in the fluent code you use it, then
it will be output indented at that level. It is basically a “child” script. Just keep in mind that
whatever you code in that .Literal()
will have to make sense and jive with the code above and
below it.
Just as with .Script()
, the .Literal()
method takes manually-entered code and its use is garbage in
garbage out so your mileage will also vary based on the quality of your code.
The second thing that the .Literal()
method does for you is that the underlying object that
it produces implements the ISqlQueryExpression
interface, which is an implementation
detail that you don’t have to deal with but essentially means that it can be used anywhere that a
query expression is used and it will be treated as such. That means that it will automatically add
your script as a child of one of the following parent SQL statements:
- SELECT
In the SELECT list
- JOIN
Can be used in JOIN conditions
- WHERE Clause
Can be used in conditions under the WHERE Clause
- Condition Group
Can be used within the scope delimted by parentheses
( ... )
, typically necessary when scoping multiple conditions withOR
- INSERT
Can be used under INSERT statements
- GROUP BY
Can be used to manually create a grouping expression
- ORDER BY
Can be used to manually create a sorting expression
- HAVING Clause
Similar to a WHERE clause it can be used in conditions under the HAVING clause
One final thing to note about .Literal()
is that it is meant for single lines. Unlike the .Script()
method you will get no such multi-line clean-up. If you need multiple lines of SQL code in the middle of
your structure then you should utilize multiple calls to the .Literal()
method, one for each line.
All that said, please READ THE WARNING BELOW!
Warning
When adding manually-crafted SQL code using .Script()
or .Literal()
you should know that it will be
vulnerable to SQL Injection attacks. Do not concatenate or string-interpolate variables containing values set
from an untrusted source like …
<shivers> a user’s data entry screen </shivers>
This, nor any other library, will protect you from a hack injected through that variable.
Please read the Security documentation to learn about the security features provided with this library as well as its limitations.
You have been warned!
Script() Example¶
var sql = TSQL
.Script(@"
DECLARE @dateVar DATETIME, @now DATETIME
SET @dateVar = DATEADD(Month, -3, GETDATE())
SET @now = GETDATE()
")
.SELECT()
.COLUMN("EmployeeID")
.COLUMN("FirstName")
.COLUMN("LastName")
.COLUMN("HireDate")
.FROM("Employees")
.WHERE("HireDate").IsGreaterThanOrEqualTo("@dateVar")
.Script(@"
EXEC [dbo].[Employee Sales by Country] @dateVar, @now
")
.Build()
;
Console.WriteLine(sql);
Output:
DECLARE @dateVar DATETIME, @now DATETIME
SET @dateVar = DATEADD(Month, -3, GETDATE())
SET @now = GETDATE()
SELECT
[EmployeeID],
[FirstName],
[LastName],
[HireDate]
FROM [Employees]
WHERE 1=1
AND [HireDate] >= @dateVar
EXEC [dbo].[Employee Sales by Country] @dateVar, @now
Literal() Example¶
var sql = TSQL
.SELECT()
.COLUMN("EmployeeID")
.COLUMN("FirstName")
.COLUMN("LastName")
.COLUMN("HireDate")
.Literal("[FirstName] + ' ' + [LastName] AS [FullName]")
.FROM("Employees")
.WHERE()
.Literal("RIGHT(DATENAME(Month, [HireDate]), 3) = 'ber'")
.Build()
;
Console.WriteLine(sql);
Output:
SELECT
[EmployeeID],
[FirstName],
[LastName],
[HireDate],
[FirstName] + ' ' + [LastName] AS [FullName]
FROM [Employees]
WHERE 1=1
AND RIGHT(DATENAME(Month, [HireDate]), 3) = 'ber'