An important thing to note in OrmLite is how the query is constructed and executed is independent to how the results are mapped. It doesn't matter whether the query is raw custom SQL or a Typed SQL Expression, OrmLite only looks at the dataset returned to workout how the results should be mapped.
So when use the Select<T>(SqlExpression<T>)
API, OrmLite will always try to map the results into the primary SqlExpression Type in db.From<DeptEmployee>()
which isn't what you want since the custom columns you've selected don't match the shape of DeptEmployee
POCO.
There are a few different ways to read a custom schema which all work off the same query (as it's independent to how you chose to map the results):
var q = db.From<DeptEmployee>()
.Join<Department2>()
.Select<DeptEmployee, Department2>(
(de, d2) => new { de.FirstName, de.LastName, d2.Name });
Our recommendation, esp. for a typed code-first ORM like OrmLite is to create a Typed Custom POCO and select that, e.g:
class Custom
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Name { get; set; }
}
db.Select<Custom>(q).PrintDump();
Which will print out a nice:
[
{
FirstName: First 1,
LastName: Last 1,
Name: Dept 1
},
]
The primary benefit is that you get Typed access to your custom results in a List<Custom>
.
If you don't want to create a custom Type you can Select OrmLite's Dynamic Result APIs, e.g:
If you're happy knowing the positions of the different fields you can select a List<object>
which will return the selected fields in the order they were selected, e.g:
db.Select<List<object>>(q).PrintDump();
Prints:
[
[
First 1,
Last 1,
Dept 1
],
]
Otherwise if you also want the names returned you can select a string object dictionary, e.g:
db.Select<Dictionary<string,object>>(q).PrintDump();
Which prints results similar to the Custom POCO, but the names and corresponding values are maintained in a loose-typed object Dictionary:
[
{
FirstName: First 1,
LastName: Last 1,
Name: Dept 1
},
]
If you were instead only selecting 2 columns, e.g:
var q = db.From<DeptEmployee>()
.Join<Department2>()
.Select<DeptEmployee, Department2>(
(de, d2) => new { de.LastName, d2.Name });
You can make of OrmLite's convenient data access APIs which will let you select 2 columns into a Dictionary<string,string>
, e.g:
db.Dictionary<string,string>(q).PrintDump();
Which prints:
{
Last 1: Dept 1,
Last 2: Dept 2,
Last 3: Dept 3
}
Notice this is very different to the string object dictionary above as it returns results in a single Dictionary<string,string>
for all rows instead of List<Dictionary<string,object>>
, which has a Dictionary for each row.
Likewise if you were only selecting 1 field, e.g:
var q = db.From<DeptEmployee>()
.Join<Department2>()
.Select(x => x.LastName);
Then you can select a singular column of results in a List<string>
, e.g:
db.Column<string>(q).PrintDump();
Which prints:
[
Last 1,
Last 2,
Last 3
]
If you instead wanted distinct results you can return them in a HashSet<string>
with:
db.ColumnDistinct<string>(q).PrintDump();
To return to the original important point, it doesn't matter how the query was constructed (which just controls the SQL that's generated), OrmLite only looks at the returned resultset to Map the results, which it tries to map to the target API that you've specified you want the results mapped into, so executing custom SQL:
db.Column<string>("SELECT LastName FROM DeptEmployee").PrintDump();
Or if you executed a Stored Procedure:
db.Column<string>("EXEC GetLastNamesFromDeptEmployees").PrintDump();
Is mapped exactly the same way if you used a typed SQL Expression, i.e. OrmLite only looks at the resultset which it maps to how you want the results returned.
.Select<List<object>>(q)
does return the individual fields, like I want, but of course the code to work with the results gets ugly! Do you think it would be possible to add support for.Select<dynamic>(q)
, which would return a list of anonymous types containing the selected fields? In this example it would be the same as yourCustom
class. This would be very useful in cases where the results are then further manipulated using LINQ (in memory), because it would keep all fields type-safe without the overhead of creating a class for every such query. – Vasques