-
Notifications
You must be signed in to change notification settings - Fork 857
Return Data
中文 | English
FreeSql uses ExpressionTree to optimize the reading speed. If you know the technology, you must know that in addition to native code under .NETCore technology, the fastest are Emit and ExpressionTree.
At the beginning, we used Reflection + Cache. Although .NETCore optimized the reflection performance, after comparing the performance with Dapper, we found that there was still a certain gap. After we refactored to an implementation based on ExpresstionTree, our performance was comparable to Dapper.
FreeSql supports many types, and the complexity of implementing ExpressionTree is relatively large. If developers are interested in this, you can browse the source code.
Topic t1 = fsql.Select<Topic>().ToOne();
The FreeSql convention is that
ToOne
/First
will always return null or entity object with data, andToList
will always return a non-null List<entity type>
List<Topic> t1 = fsql.Select<Topic>().ToList();
List<Category> t2 = fsql.Select<Category>.ToTreeList();
List<Category> t3 = fsql.Select<Category>.Where(a => a.Name = "Home Appliances").AsTreeCte().ToTreeList();
//v1.6.0 AsTreeCte() Recursive CTE query for all sub-categories under "Home Appliances"
The query data will be processed into a tree type.
Note: the entity needs to be configured with parent-child navigation properties
List<Topic> t4 = fsql.Select<Topic>().LeftJoin(a => a.Type.Id == a.TypeId).ToList();
At this time, the common field of
Topic
and theType
field of navigation property will be queried
more:Greed Loading
//Return a field
List<int> t5 = fsql.Select<Topic>().ToList(a => a.Id);
//Return anonymous class
List<ANONYMOUS_TYPE> t6 = fsql.Select<Topic>().ToList(a => new { a.Id, a.Title });
//Return tuple
List<(int, string)> t7 = fsql.Select<Topic>().ToList<(int, string)>("id, title");
//Return to navigation properties
List<ANONYMOUS_TYPE> t8 = fsql.Select<Topic>().ToList(a => new {
a.Id, a.Title,
a.Type //You can directly return the navigation property "Type"
});
//Return SQL field
List<ANONYMOUS_TYPE> t9 = fsql.Select<Topic>().ToList(a => new {
cstitle = "substr(a.title, 0, 2)", //Use substr(a.title, 0, 2) as the query field
csnow = Convert.ToDateTime("now()"), //Use now() as the query field
//Wonderful idea: how to query the result of window function
});
//Return the fields of the subquery
List<ANONYMOUS_TYPE> t10 = fsql.Select<Topic>().ToList(a => new {
a.Id,
count = fsql.Select<T2>().Count(),
max = fsql.Select<T2>().Max(b => b.Id),
min = fsql.Select<T2>().Min(b => b.Id),
name = fsql.Select<2>().First(b => b.name)
});
//Return the records of the subquery v3.2.650+
List<ANONYMOUS_TYPE> t11 = fsql.Select<Topic>().ToList(a => new {
a.Id,
list1 = fsql.Select<T2>().ToList(),
list2 = fsql.Select<T2>().Where(b => b.TopicId == a.Id).ToList()
});
List<ANONYMOUS_TYPE> t12 = fsql.Select<Topic>()
.GroupBy(a => new { a.Author })
.WithTempQuery(a => new { Author = a.Key.Author, Count = a.Count() })
.ToList(a => new {
a.Author, a.Count,
list1 = fsql.Select<T2>().ToList(),
list2 = fsql.Select<T2>().Where(b => b.Author == a.Author).ToList()
});
In the early constant mechanism, we left it to raw SQL. If you really need to return the string, you can write: "'xxx'"
Reference to: https://github.com/dotnetcore/FreeSql/issues/528
fsql.Select<Song>().ToList<Dto>();
//Case 1: The field with the same property name of Dto and Song is queried, and List<Dto> is returned
fsql.Select<Song>().ToList(a => new Dto { xxx = a.ext })
//Case 2: The field with the same property name of Dto and Song is queried, the mapping ext is adjusted, and List<Dto> is returned
fsql.Select<Song>().ToList(a => new Song { id = a.id })
//Case 3: The type specified by Lambda is the same as the type of Song, only the specified field id is queried, and List<Song> is returned
fsql.Select<Song>().ToList(a => new { id = a.id })
//Case 4: Lambda specifies an anonymous type, only queries the specified field id, and returns List<ANONYMOUS_OBJECT>
Please handle the difference carefully.
fsql.Select<Song>().ToList(a => new Dto(a.id))
//Case 5: Only query id and return List<Dto>
fsql.Select<Song>().ToList(a => new Dto(a.id) { xxx = a.ext })
//Case 6: Query id, ext and return List<Dto>
fsql.Select<Song>().ToList(a => new Song(a.id))
//Case 7: Query id and return List<Song>
fsql.Select<Song>().ToList(a => new Song(a.id) { xxx = a.ext })
//Case 8: Query id, ext and return List<Song>
All methods of GroupBy are not applicable to DTO mapping rules
This kind of mapping supports single table/multi-table, mapping before querying data (not to query all fields first and then to memory mapping).
Searching rules, searching for property names, will loop the internal object _tables
(it will grow after join query), and check the main table first until the same field is found.
For example:
Suppose A, B, and C all have id. When the queried Dto structure is: Dto {id, a1, a2, b1, b2 }
, A.id
is mapped. You can also specify the id = C.id
mapping.
Dto query only maps default fields (common attributes). For mapping objects, please use:
Navigation object: ToList(a => new Dto { Catalog = a.Catalog })
Multi table object: ToList((a, b) => new Dto { Catalog = b })
Execute queries and return data in blocks, which can reduce memory overhead. For example, if 100,000 pieces of data are read, 100 pieces of data are returned for processing each time.
var testlist1 = fsql.Select<Song>().OrderBy(a => a.Id).ToList();
var testlist2 = new List<Song>();
fsql.Select<Song>().OrderBy(a => a.Id).ToChunk(100, done => {
testlist2.AddRange(done.Object);
//done.IsBreak = true; v1.7.0 stop reading
});
//Here is a demonstration that the final data returned by testlist1 and testlist2 are the same.
All ToList
can use ToSql
to return SQL string. There are two options:
- FieldAliasOptions.AsIndex, the default option, automatically generates as1, as2, as3 .... etc. field aliases, which can prevent the problem of multiple tables with the same field.
- FieldAliasOptions.AsProperty, use the property name as the field alias, appropriately use the two-stage structure SQL and execute it again.
v3.2.666 After the parameterized query function is enabled, use withparameters to share parameterization to avoid multiple query objects from generating the same parameter name, for example: UnionAll Query
class xxx {
public int Id { get; set; }
public string Path { get; set; }
public string Title2 { get; set; }
}
List<xxx> t11 = fsql.Ado.Query<xxx>("select * from song");
List<(int, string ,string)> t12 = fsql.Ado.Query<(int, string, string)>("select * from song");
List<dynamic> t13 = fsql.Ado.Query<dynamic>("select * from song");
Note: The entity attributes of
Ado.Query
are invalid, for example,[Column(Name = "xxx")]
is invalid
fsql.Select<Topic>()
.WithSql("select * from Topic where clicks > @val", new { val = 10 })
.Page(1, 10)
.ToList()
//SELECT a.`Id`, a.`Clicks`, a.`CategoryId`, a.`Title`, a.`CreateTime`
//FROM (select * from Topic where clicks > @val) a
When
WithSql
is used multiple times,UNION ALL
query will be used
v3.2.666 UnionAll Query、WithTempQuery + FromQuery Nested Query
v3.2.666 WithMemory Query using memory data
var list = new List<Topic>();
list.Add(new Topic { ... });
list.Add(new Topic { ... });
fsql.Select<Topic>()
.WithMemory(list)
.ToList()
//SELECT a.`Id`, a.`Clicks`, a.`CategoryId`, a.`Title`, a.`CreateTime`
//FROM (
// SELECT ...
// UNION ALL
// SELECT ...
//) a
Method | Return | Parameter | Description |
---|---|---|---|
ToSql | string | Return the SQL statement to be executed | |
ToList | List<T1> | Execute a SQL query and return the records of all the fields of the T1 entity. If there are navigation properties, they will be queried and returned together. If the record does not exist, a list with Count of 0 will be returned. | |
ToList<Dto> | List<Dto> | Lambda | Execute SQL query, return the record of the specified field or Dto mapping, if the record does not exist, return the list with Count as 0. |
ToList<T> | List<T> | string field | Execute SQL query, return the record of the field specified by field, and receive it as a tuple or basic type (int, string, long). If the record does not exist, return a list with Count of 0. |
ToOne | T1 | Execute SQL query and return the first record of all fields of the T1 entity, or null if the record does not exist. | |
ToChunk | <空> | int size, Action<FetchCallbackArgs<List<T1>>> done | Execute SQL query and return data in blocks, which can reduce memory overhead. For example, if 100,000 pieces of data are read, 100 pieces of data are returned for processing each time. |
Any | bool | Execute SQL query to determine whether there is a record | |
Sum | T | Lambda | Specify a column to sum. |
Min | T | Lambda | Specify a column to find the minimum. |
Max | T | Lambda | Specify a column to find the maximum. |
Avg | T | Lambda | Specify a column to average. |