Use LINQ to construct a query

The .NET Language-Integrated Query (LINQ) query provider in Microsoft Dataverse uses standard LINQ syntax. The first step in creating a LINQ query is to identify the relevant table types and the relationships between them. You can then specify the data source and the other query parameters.

The from clause is used to return a single "root" table. The query provider can only return rows of a single table type. The orderby and select clauses must reference this root table. You can use join clauses to add rows with a relationship to the "root" table.

LINQ operators

All LINQ query expressions have a similar format. The following sections show the most common clauses in a LINQ query expression when using the Dataverse LINQ query provider.

from

When using the generated service context and early binding, use the IQueryable table set, such as AccountSet, in the generated context.

When not using the generated context, the CreateQuery method on the service context object gives you access to Dataverse table rows.

Example:

Using the generated service context:

var query1 = from c in context.ContactSet  
select c;  

Using the CreateQuery method:

var query1 = from c in context.CreateQuery<Contact>()  
select c;  

join

The join clause represents an inner join. You use the clause to work with two or more tables that can be joined with a common column value.

Example:

from c in context.ContactSet  
join a in context.AccountSet on c.ContactId equals a.PrimaryContactId.Id  

where

The where clause applies a filter to the results, often using a Boolean expression. The filter specifies which elements to exclude from the source sequence. Each where clause can only contain conditions against a single table type. A composite condition involving multiple tables is not valid. Instead, each table should be filtered in separate where clauses.

Example:

from a in context.AccountSet  
where (a.Name.StartsWith("Contoso") && a.Address1_StateOrProvince == "WA")  

orderby

The orderby operator puts the returned query columns in a specified order.

Example:

var query1 = from c in context.CreateQuery<Contact>()     
    orderby c.FullName ascending     
    select c;  
foreach ( var q in query1)     
{  
    Console.WriteLine(q.FirstName + " " + q.LastName);     
}  

select

The select clause defines the form of the data returned. The clause creates a column set based on the query expression results. You can also define an instance of a new object to work with. The newly created object using the select clause is not created on the server, but is a local instance.

Example:

select new Contact     
{  
    ContactId = c.ContactId,  
    FirstName = c.FirstName,  
    LastName = c.LastName,  
    Address1_Telephone1 = c.Address1_Telephone1     
};  

LINQ limitations

The LINQ query provider supports a subset of the LINQ operators. Not all conditions that can be expressed in LINQ are supported. The following table shows some of the limitations of the basic LINQ operators.

LINQ Operator Limitations
join Represents an inner or outer join. Only left outer joins are supported.
from Supports one from clause per query.
where The left side of the clause must be a column name and the right side of the clause must be a value. You cannot set the left side to a constant. Both the sides of the clause cannot be constants.

Supports the String functions Contains, StartsWith, EndsWith, and Equals.
groupBy Not supported. FetchXML supports grouping options that are not available with the LINQ query provider. More information: Aggregate data using FetchXmlAggregate data using FetchXml
orderBy Supports ordering by table columns, such as Contact.FullName.
select Supports anonymous types, constructors, and initializers.
last The last operator is not supported.
skip and take Supports skip and take using server-side paging. The skip value must be greater than or equal to the take value.
aggregate Not supported. FetchXML supports aggregation options that are not available with the LINQ query provider. More information: Aggregate data using FetchXml

Filter multiple tables

You can create complex .NET Language Integrated Query(LINQ) queries in Dataverse. You use multiple Join clauses with filter clauses to create a result that is filtered on columns from several tables.

The following sample shows how to create a LINQ query that works with two tables and filters the result based on values from each of the table rows.

using (ServiceContext svcContext = new ServiceContext(_serviceProxy))
{
var query_where3 = from c in svcContext.ContactSet
 join a in svcContext.AccountSet
 on c.ContactId equals a.PrimaryContactId.Id
 where a.Name.Contains("Contoso")
 where c.LastName.Contains("Smith")
 select new
 {
  account_name = a.Name,
  contact_name = c.LastName
 };

foreach (var c in query_where3)
{
 System.Console.WriteLine("acct: " +
  c.account_name +
  "\t\t\t" +
  "contact: " +
  c.contact_name);
}
}

See also

Build queries with LINQ (.NET language-integrated query)
Use late-bound Entity class with a LINQ query
Order results using table columns with LINQ
Page large result sets with LINQ
Sample: Query data using LINQ
LINQ query examples using OrganizationServiceContext with Microsoft Dataverse