Search Results for

    Show / Hide Table of Contents

    Query Data with Venflow

    Warning

    Be carful while dealing with raw SQL and ensure that you never pass user modified SQL to any of the methods. Instead use parameterized and lambda overloads, or the Interpolated siblings.

    Warning

    The primary key always has to be present and it has to be the first column of any given table returned by a SQL Query.

    Query data without relations

    Your Database class exposes Table<T> properties which expose query operations. In Venflow queries are based on hand-written SQL. In this case we query the first 10 blogs in the database.

    await using var database = new BlogDatabase(); // You should register this in a Transient/Scoped your IOC Container.
    
    // You can re-use this in different BlogDatabase instances through the database.Blogs.QueryAsync() method
    // If you intend to reuse the query below you need to pass the QueryBatch method false for the disposeCommand,
    // otherwise the underyling command will be disposed after the first use.
    var query = database.Blogs.QueryBatch(@"SELECT * FROM ""Blogs"" LIMIT 10").Build(); 
    
    var blogs = await query.QueryAsync(); // You can also inline this with the line above.
    

    Additionally if you do not intend to reuse the the command instance you can omit the Build method call and directly call QueryAsync.

    Also, if you instead only wanted to query the first result, you can use the QuerySingle API.

    var blog = await database.Blogs.QuerySingle(@"SELECT * FROM ""Blogs"" LIMIT 1").QueryAsync();
    

    Query data with relations

    In this case we want to get the first 5 blogs with all of their posts. If you want to perform a join, the builder exposes the JoinWith and the ThenWith method to perform nested joins.

    const string sql = 
    @"SELECT * FROM 
    (
    	SELECT * FROM ""Blogs""
    	LIMIT 5
    ) AS ""Blogs"" 
    JOIN ""Posts"" ON ""Posts"".""BlogId"" = ""Blogs"".""Id""";
    
    var blogs = await database.Blogs.QueryBatch(sql).JoinWith(x => x.Posts).QueryAsync();
    

    If you instead only wanted to query the first blog with all of its posts, you can again use the QuerySingle API.

    var blog = await database.Blogs.QuerySingle().JoinWith(x => x.Posts).QueryAsync();
    
    Warning

    When joining with multiple relations, ensure that the order of joins configured with Venflow, are equal to the order of joins in the SQL.

    Queries with parameters

    Most of the times your query contains some sort of parameters. With Venflow you have two options, either by using the raw NpgsqlParameter class and the matching QuerySingle/QueryBatch overloads or the Interpolated SQL methods. You can learn more about string interpolation in this guide.

    In this example, we try to query the first blog with the id 5 with all of its posts.

    FormattableString sql =
    $@"SELECT * FROM 
    (
    	SELECT * FROM ""Blogs""
    	WHERE ""Id"" = {5}
    	LIMIT 1
    ) AS ""Blogs"" 
    JOIN ""Posts"" ON ""Posts"".""BlogId"" = ""Blogs"".""Id""";
    
    var blog = await database.Blogs.QueryInterpolatedSingle(sql).JoinWith(x => x.Posts).QueryAsync();
    
    Note

    Most of the methods in Venflow which accept raw SQL do have a sibling method called *Interpolated*.

    Query with refactorable SQL

    All Query* methods do contain an overload with a Func<T, FormattableString> parameter. This will not only allow for usual string interpolation like the Query*Interpolated methods, but also for refactorable SQL.

    var id = 1;
    
    var blog = await Database.Blogs.QuerySingle(b => $"SELECT * FROM {b} WHERE {b.Id} = {id}").QueryAsync();
    

    This would result in the following SQL:

    -- @p1 will contain the value '1'
    SELECT * FROM "Blogs" WHERE "Blogs"."Id" = @p1 
    
    Note

    As the lambda is converted to an expression tree under the hood, try to keep computations as low as possible inside the interpolated string itself e.g. {}, in order to reduce the memory footprint as well as to improve the performance. Instead try to compute everything before querying and store these results in locals which then can used inside the interpolated SQL.

    Query relations with refactorable SQL

    Querying with relations works quite similar as in the example above.

    var id = 1;
    
    var blog = await Database.Blogs.QuerySingle<Post>(
    	(b, p) => 
    	$"SELECT * FROM {b} LEFT JOIN {p} ON {p.BlogId} = {b.Id} WHERE {b.Id} = {id}"
    	).JoinWith(x => x.Posts).QueryAsync();
    

    This would result in the following SQL:

    -- @p1 will contain the value '1'
    SELECT * FROM "Blogs" 
    LEFT JOIN "Posts" ON "Posts"."BlogId" = "Blogs"."Id"
    WHERE "Blogs"."Id" = @p1 
    
    Note

    As the lambda is converted to an expression tree under the hood, try to keep computations as low as possible inside the interpolated string itself e.g. {}, in order to reduce the memory footprint as well as to improve the performance. Instead try to compute everything before querying and store these results in locals which then can used inside the interpolated SQL.

    Query partial data

    The beautiful thing about Venflow is that you can only query for partial data, which means that a query doesn't necessarily has to return all column. There are only two thing you need to be aware of:

    • The primary key always needs to be returned
    • Assuming you have two tables, table A and table B, which you are joining together. Table A isn't allowed to contain a column (other than the primary key) to have the same name as the primary key of table B. Otherwise Venflow won't be able to know when to spilt the SQL result.

    A simple example of that would be something like the following, where we just query the name and the primary key of all blogs.

    const string sql = @"SELECT ""Id"", ""Name"" FROM ""Blogs""";
    
    var blogs = await database.Blogs.QueryBatch(sql).QueryAsync();
    

    Queries which don't return entities

    In Venflow you have the option to construct queries which don't necessarily return a row of a table, in this case you can use the Custom<T> method on your Database class.

    In the following example we want to return the amount of rows in the Blogs table.

    public class CountReturn
    {
        public int Count { get; set; }
    }
    
    await database.Custom<CountReturn>().QuerySingle(@"SELECT COUNT(*) FROM ""Blogs""").QueryAsync();
    
    Warning

    This API does not support any of the usual methods available on regular entities, such as change tracking or joins.

    Theme

    • Improve this Doc
    Back to top Copyright © 2021 Twenty