Skip to main content

Select

nicyeAbout 5 minAbout 1453 words

Select

FreeSql has invested heavily in querying data, offering features like fluent style, multi-table queries, expression functions, and strong support for navigation properties.

《Paging Queries》《Repository Layer》《Read-Write Separation》
《Single Table Queries》《Filters》
《Multi-Table Queries》《Lazy Loading》《Performance》
《Nested Queries》《Eager Loading》《Sharding》
《Group By Aggregation Queries》《Expression Functions》《Multi-Tenancy》
《Return Data》

Expression Functions

DescriptionLambda ExpressionSQL
inWhere(a => new [] { 1,2,3 }.Contains(a.Id))[Id] in (1,2,3)
not inWhere(a => !new [] { 1,2,3 }.Contains(a.Id))[Id] not in (1,2,3)
Multi-column inWhere(a => list.Any(b => b.Item1 == a.Id && b.Item2 == a.ct1))([Id]=1 and [ct1]=1) or ([Id]=2 and [ct1]=2)
like '%xxx%'Where(a => a.Title.Contains("xxx"))[Title] like '%xxx%'
like 'xxx%'Where(a => a.Title.StartsWith("xxx"))[Title] like 'xxx%'
like '%xxx'Where(a => a.Title.EndsWith("xxx"))[Title] like '%xxx'
Date rangeWhere(a => a.Time.Between(time1, time2))[Time] between @time1 and @time2
Exists.Any()select 1 from ...
Count.Count()select count(*) from ...
Sum.Sum(a => a.Score)select sum([Score]) from ...
Average.Avg(a => a.Score)select avg([Score]) from ...
Maximum.Max(a => a.Score)select max([Score]) from ...
Minimum.Min(a => a.Score)select min([Score]) from ...

For more details, see 《Expression Functions》

SqlServer WithLock/WithIndex

var list = fsql.Select<Region>()
    .WithLock()
    .Limit(1).ToList();
//SELECT TOP 1 ... FROM [Region] a With(NoLock)

var list = fsql.Select<Region>()
    .WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
    .Limit(1).ToList();
//SELECT TOP 1 ... FROM [Region] a With(NoLock, NoWait)

var list = fsql.Select<Region>()
    .WithLock()
    .WithIndex("idx_01")
    .Limit(1).ToList();
//SELECT TOP 1 ... FROM [Region] a With(index=idx_01, NoLock)

Multi-table:

var list = Select<Region, T2>()
    .InnerJoin((a, b) => a.x == b.xx)
    .WithLock(SqlServerLock.NoLock, new Dictionary<Type, bool>
    {
        [typeof(T2)] = false
    })
    .WithIndex("idx_01", new Dictionary<Type, string>
    {
        [typeof(T2)] = "idx_02"
    })
    .Limit(1).ToList();
//SELECT TOP 1 ..
//FROM [Region] a With(index=idx_01, NoLock) 
//INNER JOIN [T2] b With(index=idx_02) ON a.[x] = b.[xx]

Global NoLock Setting:

//Applies to all entity classes
fsql.SetGlobalSelectWithLock(SqlServerLock.NoLock, null);

//【Specific】entity classes
fsql.SetGlobalSelectWithLock(SqlServerLock.NoLock, new Dictionary<Type, bool>
{
    [typeof(Region)] = true,
    [typeof(T2)] = true
});

Dynamic Filtering WhereDynamicFilter

《Efficient Understanding of FreeSql WhereDynamicFilter and Insights into Its Design》open in new window

The ISelect.WhereDynamicFilter method implements dynamic filtering conditions (interacting with the frontend), supporting the following operators:

  • Contains/StartsWith/EndsWith/NotContains/NotStartsWith/NotEndsWith: Contains/Does not contain, like '%xx%', or like 'xx%', or like '%xx'
  • Equal/NotEqual: Equals/Not equals
  • GreaterThan/GreaterThanOrEqual: Greater than/Greater than or equal
  • LessThan/LessThanOrEqual: Less than/Less than or equal
  • Range: Range query
  • DateRange: Date range, with special handling value[1] + 1
  • Any/NotAny: Whether it matches any item in value (essentially SQL IN)
  • Custom: Custom parsingopen in new window
DynamicFilterInfo dyfilter = JsonConvert.DeserializeObject<DynamicFilterInfo>(@"
{
  ""Logic"": ""And"",
  ""Filters"":
  [
    { ""Field"": ""id"", ""Operator"": ""Equals"", ""Value"": 1 },
    {
      ""Logic"": ""Or"",
      ""Filters"":
      [
        { ""Field"": ""id"", ""Operator"": ""Equals"", ""Value"": 2 },
        { ""Field"": ""id"", ""Operator"": ""Equals"", ""Value"": 3 }
      ]
    }
  ]
}");
fsql.Select<Region>().WhereDynamicFilter(dyfilter).ToList();
//WHERE id = 1 AND (id = 2 OR id = 3)

Dynamic Table Names: ISelect.AsTable((t, old) => $"{old}_201903")

Dynamic Sorting: ISelect.OrderByPropertyName("Parent.Code")

Dynamic Returns: ISelect.ToDataTableByPropertyName(new string[] { "Parent.Code", "Id" })

Dynamic Eager Loading: ISelect.IncludeByPropertyName("Parent.Parent").IncludeByPropertyName("Parent.Childs")

Clone Queries ISelect

For your information: C# 7.0 supports local functions, which allows defining temporary methods within a method. This feature is highly recommended as it is very effective in many scenarios.

When a method is defined inside another method, it is called: local function/nested method.

public void Test()
{
    ISelect<AdmRoute> getSelect() => fsql.Select<AdmRoute>().Include(a => a.Parent)
        .WhereIf(!string.IsNullOrEmpty(key), a => a.Name.Contains(key) || ...)
        .WhereIf(Parent_Id?.Any() == true, a => Parent_Id.Contains(a.ParentId))
        .WhereIf(mn_Roles_Id?.Any() == true, a => a.Roles.Any(b => mn_Roles_Id.Contains(b.Id)));

    var select1 = getSelect();
    var select2 = getSelect();
    select1.Where(a => a.Status == 0);
    // At this point, select2 will not have the a.Status == 0 condition
}

API

MethodReturn TypeParametersDescription
ToSqlstringReturns the SQL statement to be executed
ToListList<T1>Executes SQL query and returns records of all fields of the T1 entity; if navigation properties exist, they are also queried and returned. If no records exist, returns a list with Count 0.
ToList<T>List<T>LambdaExecutes SQL query and returns records of specified fields; if no records exist, returns a list with Count 0.
ToList<T>List<T>string fieldExecutes SQL query and returns records of the field specified, and can be received as a tuple or basic types (int, string, long); if no records exist, returns a list with Count 0.
ToOneT1Executes SQL query and returns the first record of all fields of the T1 entity; if no record exists, returns null.
ToAggregate<T>List<T>LambdaExecutes SQL query and returns aggregate results of specified fields (suitable for scenarios where GroupBy is not required).
AnyboolExecutes SQL query to check if there are any records.
SumTLambdaComputes the sum of a specified column.
MinTLambdaComputes the minimum value of a specified column.
MaxTLambdaComputes the maximum
MaxTLambdaSpecifies the maximum value of a column
AvgTLambdaSpecifies the average value of a column
【Pagination】
CountlongThe number of records in the query
Count<this>out longThe number of records in the query, returned as an out parameter
Skip<this>int offsetOffset the number of rows in the query
Offset<this>int offsetOffset the number of rows in the query
Limit<this>int limitSpecify the number of data records to query
Take<this>int limitSpecify the number of data records to query
Page<this>int pageIndex, int pageSizePagination
【Condition】
Where<this>LambdaSupports multi-table query expressions; using multiple times is equivalent to AND
WhereIf<this>bool, LambdaSupports multi-table query expressions
Where<this>string, parmsNative SQL syntax condition, Where("id = @id", new { id = 1 } ,Note the prefix @, according to the specific database not explained elsewhere. Same applies)
WhereIf<this>bool, string, parmsNative SQL syntax condition, WhereIf(true, "id = @id", new { id = 1 }
WhereCascade<this>LambdaAdd conditions to each table in multi-table queries
WhereDynamicFilter<this>DynamicFilterInfoDynamic filtering conditions (interaction with the frontend)
【GroupBy】
GroupBy<this>LambdaGroup by selected columns, GroupBy(a => a.Name)GroupBy(a => new{a.Name,a.Time})
GroupBy<this>string, parmsGroup by native SQL syntax, GroupBy("concat(name, @cc)", new { cc = 1 })
Having<this>string, parmsFilter aggregation conditions by native SQL syntax, Having("count(name) = @cc", new { cc = 1 })
Disdinct<this>.Distinct().ToList(x => x.GroupName) is for a specific field
【Sort】
OrderBy<this>LambdaSort by column, OrderBy(a => a.Time), can be used multiple times
OrderByDescending<this>LambdaSort by column in descending order, OrderByDescending(a => a.Time)
OrderBy<this>string, parmsSort by native SQL syntax, OrderBy("count(name) + @cc", new { cc = 1 })
OrderByPropertyNamestring, boolSort by property name string (supports navigation properties)
【Multi-tables】
LeftJoin<this>LambdaLeft join query, supports navigation properties or specifying associated entity types
InnerJoin<this>LambdaInner join query, supports navigation properties or specifying associated entity types
RightJoin<this>LambdaRight join query, supports navigation properties or specifying associated entity types
LeftJoin<this>string, parmsLeft join query using native SQL syntax, LeftJoin("type b on b.id = a.id and b.clicks > @clicks", new { clicks = 1 })
InnerJoin<this>string, parmsInner join query using native SQL syntax, InnerJoin("type b on b.id = a.id and b.clicks > @clicks", new { clicks = 1 })
RightJoin<this>string, parmsRight join query using native SQL syntax, RightJoin("type b on b.id = a.id and b.clicks > @clicks", new { clicks = 1 })
From<this>LambdaMulti-table queries, very convenient for more than 3 tables; currently supports up to 10 tables
FromQueryISelect<T1, T2>ISelect<T2>Single table into double table query
WithTempQueryISelect<T1>LambdaNest single or multiple table queries into a single table query
WithMemoryISelect<T1>List<T1>Query using in-memory data
UnionAllISelect<T1>ISelect<T1>[]Union query
【Other】
As<this>string alias = "a"Specify alias
Master<this>Specify querying from the master database (default is querying from the slave database)
CommandTimeout<this>intCommand timeout setting (seconds)
WithTransaction<this>DbTransactionSet transaction object
WithConnection<this>DbConnectionSet connection object
WithLock<this>EnumSpecial settings like SqlServer NoLock
ForUpdate<this>boolExclusive update lock, adapted for different databases, detailed explanation in comments
AsQueryableIQueryableConvert ISelect to IQueryable, mainly used for extension, e.g., abp IRepository GetAll() interface method needs to return IQueryable object. Note: IQueryable methods are more likely to cause pollution, so avoid this conversion as much as possible
ToTreeList()List<TEntity>NoneReturn hierarchical data in the form of a TreeList
AsTreeCte()ISelect(up, pathSelector, level)Recursive query of hierarchical tables