-
Notifications
You must be signed in to change notification settings - Fork 4
Queries
LINQ provides an intuitive, statically typed means of querying resources without needing to understand the underlying SData URL components, particularly the filter expression language.
Note: LINQ was introduced in .NET 3.5 so the .NET 2.0 version of this library doesn't support LINQ queries.
Queries automatically handle paging, so a single query might span multiple requests. The following example requests a list of active contacts ordered by last name then first name with addresses included.
var client = new SDataClient("http://example.com/sdata/slx/dynamic/-/")
{
UserName = "admin",
Password = "password"
};
var contacts = await client.Query<Contact>()
.Where(c => c.Status == "Active")
.OrderBy(c => c.LastName)
.ThenBy(c => c.FirstName)
.Fetch(c => c.Address)
.ToListAsync();
[SDataPath("contacts")]
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Status { get; set; }
public Address Address { get; set; }
}
The SDataPath
attribute on the contact POCO specifies the path of the resource relative to the base URL of the client object. Without this attribute the resource path would need to be specified every time a query is created.
Selecting only the required properties is a good way to reduce the amount of data fetched from the server. This is accomplished using the standard Select
operator. The LINQ provider finds all referenced properties in the projection lambda expression and builds a minimal SData select argument. The following example performs the same contact query as above but selects a subset of the available properties into an anonymous type.
var contacts = await client.Query<Contact>()
.Where(c => c.Status == "Active")
.OrderBy(c => c.LastName)
.ThenBy(c => c.FirstName)
.Select(c => new {c.LastName, c.FirstName, c.Address.City, c.Address.State})
.ToListAsync();
In addition to the contact name properties, two address properties are also pulled into the result object. The additive Fetch
operator has been removed because the subtractive Select
operator takes precedence. There is currently no way to limit the selected properties without changing the resource type, which means the query returns anonymously typed objects that cannot be updated.
The following standard LINQ operators are supported.
- All
- Any
- ElementAt[OrDefault]
- First[OrDefault]
- Last[OrDefault]
- [Long]Count
- OrderBy[Descending]
- Select
- Single[OrDefault]
- Skip
- Take
- ThenBy[Descending]
- ToArray
- ToDictionary
- ToList
- ToLookup
- Where
Grouping, joining, aggregation and set based operations are not supported due to SData protocol limitations. These operations can still be used in-memory once the query is materialized using ToList
or ToArray
, however it's important to understand the data transfer implications when doing so.
In addition to the standard operators, the following extension operators are available:
-
Fetch
: Specify related resources and collections that should be included in the results. -
WithPrecedence
: Set the payload control precedence threshold. Setting this to zero is a convenient way to request empty resources with only protocol properties such as$key
present. -
WithExtensionArg
: Append underscore prefixed extension arguments to the query string of the generated URL.
The following methods are supported in filter predicates. They are mapped to standard SData functions that are evaluated on the server side.
- String
- Math
- DateTime
- DateTimeOffset
The following extension methods are available in addition to the ones above.
- Ascii
- Between
- Char
- In
- Left
- Like
- Right
Refer to section 2.12 of the SData specification for definitions and usage examples.
The LINQ provider also recognizes string indexer properties, making untyped queries on SDataResource
possible. A path should be provided when using this approach since it cannot be automatically determined the usual way via the SDataPath
attribute. The following example performs the same contact query as above but without the need for a contact POCO.
var contacts = await client.Query("contacts")
.Where(c => c["Status"] == "Active")
.OrderBy(c => c["LastName"])
.ThenBy(c => c["FirstName"])
.Fetch(c => c["Address"])
.ToListAsync();
When using the .NET 2.0 version of this library query requests must be built manually. The following example makes the same contact query used above but using the Execute
method directly.
var param = new SDataParameters
{
Where = "Status eq 'Active'",
OrderBy = "LastName,FirstName",
Include = "Address"
};
var results = await client.ExecuteAsync<IList<Contact>>(param);
var contacts = results.Content;
This approach doesn't automatically handle paging the way LINQ queries do.
More information on queries can be found in section 6 of the SData specification.