xpo-8914-query-and-shape-data-direct-sql-queries.md
In XPO, you can execute direct SQL queries against a database and obtain query results as scalar values, result sets or object collections.
To execute a SQL statement that does not produce a result set, call the Session.ExecuteNonQuery method as shown below.
unitOfWork.ExecuteNonQuery("UPDATE [Northwind].[dbo].[Order Details]" +
"SET [Discount] = 0.15 WHERE [UnitPrice] > 100");
unitOfWork.ExecuteNonQuery("UPDATE [Northwind].[dbo].[Order Details]" &
"SET [Discount] = 0.15 WHERE [UnitPrice] > 100")
To execute a SQL query and obtain a scalar value, call the Session.ExecuteScalar method.
public int GetEmployeeOrdersCount(int employeeId) {
return (int)unitOfWork.ExecuteScalar(string.Format(
"SELECT COUNT(*) FROM [Northwind].[dbo].[Orders] " +
"WHERE [EmployeeID] = {0}", employeeId));
}
Public Function GetEmployeeOrdersCount(ByVal employeeId As Integer) As Integer
Return CInt(Fix(unitOfWork.ExecuteScalar(
String.Format("SELECT COUNT(*) FROM [Northwind].[dbo].[Orders] " &
"WHERE [EmployeeID] = {0}", employeeId))))
End Function
To execute a SQL query and obtain a result set, call the Session.ExecuteQuery method.
using DevExpress.Xpo.DB;
// ...
static string queryString = "SELECT EmployeeID, (FirstName + ' ' " +
"+ LastName) as Name, City, Country FROM " +
"[Northwind].[dbo].[Employees]";
public SelectedData GetEmployeesSimpleData() {
return unitOfWork.ExecuteQuery(queryString);
}
Imports DevExpress.Xpo.DB
' ...
Private Shared queryString As String = "SELECT EmployeeID, (FirstName + ' ' " &
"+ LastName) as Name, City, Country FROM " &
"[Northwind].[dbo].[Employees]"
Public Function GetEmployeesSimpleData() As SelectedData
Return unitOfWork.ExecuteQuery(queryString)
End Function
To visualize query results, you can:
To accomplish this, you need to provide a non-persistent class whose members specify a result set’s column structure. This class will be used to map result set columns to XPDataView columns or object properties.
In the following code example, the EmployeeSimple class corresponds to a result set returned via the GetEmployeesSimpleData function shown above. This class is used to populate an XPDataView with columns, and to obtain a collection of objects from a result set.
[NonPersistent]
public class EmployeeSimple : XPLiteObject {
[Key]
public int EmployeeID {
get { return fEmployeeID; }
set { SetPropertyValue(nameof(EmployeeID), ref fEmployeeID, value); }
}
int fEmployeeID;
public string Name {
get { return fName; }
set { SetPropertyValue(nameof(Name), ref fName, value); }
}
string fName;
public string City {
get { return fCity; }
set { SetPropertyValue(nameof(City), ref fCity, value); }
}
string fCity;
public string Country {
get { return fCountry; }
set { SetPropertyValue(nameof(Country), ref fCountry, value); }
}
string fCountry;
public EmployeeSimple(Session session) : base(session) { }
}
// ...
// Populate an XPDataView with columns based on the auxiliary class.
xpDataView1.PopulateProperties(unitOfWork.GetClassInfo<EmployeeSimple>());
// Load data from a query's result set to an XPDataView.
xpDataView1.LoadData(GetEmployeesSimpleData());
// Retrieve data from a query into a collection of objects.
ICollection<EmployeeSimple> collection =
unitOfWork.GetObjectsFromQuery<EmployeeSimple>(queryString);
<NonPersistent()> _
Public Class EmployeeSimple
Inherits XPLiteObject
<Key> _
Public Property EmployeeID() As Integer
Get
Return fEmployeeID
End Get
Set(ByVal value as Integer)
SetPropertyValue(NameOf(EmployeeID), fEmployeeID, value)
End Set
End Property
Private fEmployeeID As Integer
Public Property Name() As String
Get
Return fName
End Get
Set(ByVal value as String)
SetPropertyValue(NameOf(Name), fName, value)
End Set
End Property
Private fName As String
Public Property City() As String
Get
Return fCity
End Get
Set(ByVal value as String)
SetPropertyValue(NameOf(City), fCity, value)
End Set
End Property
Private fCity As String
Public Property Country() As String
Get
Return fCountry
End Get
Set(ByVal value as String)
SetPropertyValue(NameOf(Country), fCountry, value)
End Set
End Property
Private fCountry As String
Public Sub New(ByVal session As Session)
MyBase.New(session)
End Sub
End Class
' ...
' Populate an XPDataView with columns based on the auxiliary class.
xpDataView1.PopulateProperties(unitOfWork.GetClassInfo(Of EmployeeSimple)())
' Load data from a query's result set to an XPDataView.
xpDataView1.LoadData(GetEmployeesSimpleData())
' Retrieve data from a query into a collection of objects.
Dim collection As ICollection(Of EmployeeSimple) =
unitOfWork.GetObjectsFromQuery(Of EmployeeSimple)(queryString)
If you do not want to show all class members in an XPDataView or if their order differs from the result set, then you can provide additional mapping information to obtain the proper columns in the correct order, as shown below.
static string queryOrderedString = "SELECT (FirstName + ' ' + LastName) " +
"as Name, Country, EmployeeID FROM [Northwind].[dbo].[Employees]";
public SelectedData GetEmployeesSimpleDataOrdered()
{
// Columns are mixed and the 'City' column is removed from the query.
return unitOfWork1.ExecuteQuery(queryOrderedString);
}
// Define a mapping array that specifies the order of columns in a result set.
static LoadDataMemberOrderItem[] employeesLoadOrder = new LoadDataMemberOrderItem[]
{
new LoadDataMemberOrderItem(2, "EmployeeID"),
new LoadDataMemberOrderItem(0, "Name"),
new LoadDataMemberOrderItem(1, "Country")
};
// Populate an XPDataView with columns and load data using the specified mapping array.
xpDataView1.PopulatePropertiesOrdered(unitOfWork.GetClassInfo<EmployeeSimple>(), employeesLoadOrder);
xpDataView1.LoadOrderedData(employeesLoadOrder, GetEmployeesSimpleDataOrdered());
// Retrieve data from a result set into a collection of objects using the specified mapping array.
ICollection<EmployeeSimple> collection =
unitOfWork.GetObjectsFromQuery<EmployeeSimple>(employeesLoadOrder, queryOrderedString);
Private Shared queryOrderedString As String = "SELECT (FirstName + ' ' + LastName) " &
"as Name, Country, EmployeeID FROM [Northwind].[dbo].[Employees]"
Public Function GetEmployeesSimpleDataOrdered() As SelectedData
' Columns are mixed and the 'City' column is removed from the query.
Return unitOfWork1.ExecuteQuery(queryOrderedString)
End Function
' Define a mapping array that specifies the order of columns in a result set.
Private Shared employeesLoadOrder() As LoadDataMemberOrderItem =
{
New LoadDataMemberOrderItem(2, "EmployeeID"),
New LoadDataMemberOrderItem(0, "Name"),
New LoadDataMemberOrderItem(1, "Country")
}
' Populate an XPDataView with columns and load data using the specified mapping array.
xpDataView1.PopulatePropertiesOrdered(unitOfWork.GetClassInfo(Of EmployeeSimple)(), employeesLoadOrder)
xpDataView1.LoadOrderedData(employeesLoadOrder, GetEmployeesSimpleDataOrdered())
' Retrieve data from a result set into a collection of objects using the specified mapping array.
Dim collection As ICollection(Of EmployeeSimple) =
unitOfWork.GetObjectsFromQuery(Of EmployeeSimple)(employeesLoadOrder, queryOrderedString)
The examples above demonstrate a strongly-typed approach, where XPDataView automatically retrieves properties from a non-persistent classe. XPDataView also can work in untyped mode. To use XPDataView without non-persistent classes, populate the XPDataView.Properties collection:
Session session = new Session();
SelectedData data = session.ExecuteSproc("sprocName", parameters);
IList<string> propertyNames = new List<string>() { "ProductName", "Total" };
IList<Type> propertyTypes = new List<Type>() { typeof(string), typeof(int) };
XPDataView dataView = new XPDataView(session.Dictionary, propertyNames, propertyTypes);
dataView.LoadData(data);
Dim session As New Session()
Dim data As SelectedData = session.ExecuteSproc("sprocName", parameters)
Dim propertyNames As IList(Of String) = New List(Of String)() From {"ProductName", "Total"}
Dim propertyTypes As IList(Of Type) = New List(Of Type)() From {GetType(String), GetType(Integer)}
Dim dataView As New XPDataView(session.Dictionary, propertyNames, propertyTypes)
dataView.LoadData(data)
See Also