Starcounter
HomeDownloadDocsCommunity
2.3.2
2.3.2
  • Starcounter Documentation
  • Getting Started
  • Starcounter
    • Collapsing the Stack
      • Complexity and Scalability Tradeoff
      • The Future of Micro-Services
      • 10 Benefits of Collapsing the Stack
    • Integrated Database and Web Server
  • Hello World - Tutorial
    • Create a Database Class
    • Create a Real Time UI
    • First Interactive UI
    • Computed Properties
    • Expense Tracker
    • Cancel and Delete
    • The Next Step
  • Guides
    • Database
      • Database Classes
      • Data manipulation
      • Object Identity and Object References
      • Querying with SQL
      • Data Types
      • Relations
      • Inheritance
      • Sharing data
      • Database Configuration
      • Comparing Database Objects
      • Referential Integrity and Constraints
    • SQL
      • Identifiers
      • Path Expressions
      • Data operators
      • Joins
      • Aggregates
      • Comparisons and Logical Operators
      • Sorting
      • Fetch
      • Offset Key
      • Indexes
      • Literals
      • Query Plan Hints
      • Reserved words
      • Query for Database Classes
      • SQL Isolation Between Applications
    • Transactions
      • Short-Running Transactions
      • Long running transactions
      • Using Transactions
      • Running Background Jobs
      • Commit Hooks
      • Post-commit hooks
    • Typed JSON
      • JSON-by-example
      • Code-Behind
      • Data Bindings
      • Callback Methods
      • Responding with JSON
      • Accepting JSON in Requests
      • Primitive Arrays and Single Value Types
      • Typed JSON Internals
    • Blendable Web Apps
      • Starcounter MVVM
      • Palindrom
      • Client-Side Stack
      • Sessions
      • HTML Views
      • App Shell
      • Web Components
      • View Attaching
      • View Composing
      • HTML Compositions
      • HTML Views Blending Guidelines
      • Avoiding CSS conflicts
      • Debugging
    • Network
      • HTTP
      • Internal Self Calls
      • Middleware
      • Anonymous or Substitute Handlers
      • URL Aliases and Redirects
      • Network Gateway
      • Static File Server
      • WebSocket
      • Avoiding URI conflicts
      • TCP Sockets
      • UDP Sockets
    • Publishing Apps
    • Working with Starcounter
      • Release Channels
      • Installation
      • Starting and Stopping Apps
      • Administrator Web UI
      • Star CLI
      • StarAdmin CLI
      • StarDump CLI
      • Working in Visual Studio
      • Error Log
      • Using HTTPS on NGINX
      • Using HTTPS on IIS
      • Run Starcounter in Production
      • Weaver
      • Investigating App Crashes
      • Configuration Structure
      • Database Refactoring
      • Using Unload/Reload to Modify Database Schema
      • Kernel Questions and Answers
      • Log Files
  • Cookbook
    • Attach an HTTP Request to an Existing Long-Running Transaction
    • Cookie-Based Authentication
    • Timestamp on Object Creation
    • Creating Strongly Typed JSON Collections
    • Migrating From 2.2 to 2.3+
    • Multiple Pages
    • Icons
    • Proposed Project Structure
    • Acceptance Testing with Selenium
    • Requesting a User to Authenticate
    • How to delete unused tables and columns
Powered by GitBook
On this page
  • Introduction
  • Return Types
  • Making Queries Less Fragile
  • Using Variables
  • Query Processing Error
  1. Guides
  2. Database

Querying with SQL

PreviousObject Identity and Object ReferencesNextData Types

Last updated 7 years ago

Introduction

Data stored in the database can be queried for with SQL queries. The query is passed as a string to the Db.SQL method. The allowed SQL syntax is covered in the section.

In addition to querying the database with SQL, you can also use LINQ by using the package . Documentation for Starcounter.Linq is in in the ,

Return Types

SQL queries are executed with the Db.SQL method. If the SQL command is SELECT, the function returns Starcounter.QueryResultRows<T> : IEnumerable<T>, it otherwise returns null.

Db.SQL("SELECT p FROM Person p"); // => QueryResultRows<Person>
Db.SQL("DELETE FROM Person"); // => null

T in QueryResultRows<T> is the type of the object retrieved if the whole object is retrieved, otherwise, it's Starcounter.Query.Execution.Row.

Db.SQL("SELECT p FROM Person p"); // => QueryResultRows<Person>
Db.SQL("SELECT p.Name FROM Person p"); // => QueryResultRows<Query.Execution.Row>

We recommend avoiding Starcounter.Query.Execution.Row when possible and instead retrieve the whole object and filter out the needed properties with Linq.

Db.SQL("SELECT p.Name FROM Person p"); // Not recommended
Db.SQL("SELECT p FROM Person p")
    .Select(p => new { p.Name }); // Recommended

In addition to traditional SQL, Starcounter allows you to select objects in addition to primitive types such as strings and numbers. Also, it allows you to use C# style path expressions such as person.FullName.

When writing queries with Db.SQL, keep in mind that there are that should be escaped. That is done by surrounding the reserved word in quotation marks.

Making Queries Less Fragile

Since the queries are strings, they are sensitive to refactorings, for example if a database class is renamed. To make the queries less fragile, typeof and nameof can be used:

Db.SQL($"SELECT p FROM {typeof(Person)} p");
Db.SQL($"SELECT p.{nameof(Person.Name)} FROM {typeof(Person)} p");

If the query is executed many times, constructing the string every time can become a performance problem. In that case, the string can be constructed once and stored in a static property.

Using Variables

SQL variables are represented by question marks (?) in the query string, and you pass the current values of the variables as parameters to the method Db.SQL.

var employees = Db.SQL<Employee>(
  "SELECT e FROM Employee e WHERE e.FirstName = ?", "Joe");
  
foreach (var employee in employees)
{
  Console.WriteLine($"{employee.FirstName} {employee.LastName}");
}

Db.SQLtakes an arbitrary number of variables as long as the number of variable values are the same as the number of variables in the query string. Otherwise, an ArgumentException will be thrown.

var lastName = "Smith";
Employee manager; //Assume some value is assigned to the variable manager.

var employees = Db.SQL<Employee>(
  "SELECT e FROM Employee e WHERE e.LastName = ? AND e.Manager = ?", 
  lastName, manager);
  
foreach (var employee in employees)
{
  Console.WriteLine($"{employee.LastName}; {emp.Manager.LastName}");
}

Each variable has an implicit type depending on its context in the query string. For example, a variable that is compared with a property of type string will implicitly be of the type string. If a variable is given a value of some incompatible type, then an InvalidCastException will be thrown. All numerical types are compatible with each other.

You can only use ? for variables after the WHERE clause. You can't, for instance, use ? to replace the class name of a query.

Query Processing Error

If a query cannot be processed due to some syntax or type checking error then the method Db.SQL will throw the SqlException ScErrSQLIncorrectSyntax (SCERR7021).

try
{  
    var people = Db.SQL<Person>("SELECT e.NonExistingProperty FROM Person p");
    
    foreach(Person person in people)  
    {    
        Console.WriteLine(person.Name);  
    }
}
catch (SqlException exception)
{  
    Console.WriteLine("Incorrect query: " + exception.Message);
}

The QueryResultRows class is deprecated from Starcounter 2.3.1. Read about the changes here:

SQL
Starcounter.Linq
Starcounter.Linq repository on GitHub
certain reserved words
https://starcounter.io/reducing-magic-increasing-familiarity-obsoleting-queryresultrows/