Linq to Sharepoint "where" clause cannot be found - linq

Hello stackoverflowers,
I'm trying to use LINQ to Sharepoint for the first time, but my where keyword isn't recognized : "Could not find an implementation of the query pattern for source type 'Microsoft.SharePoint.SPList'. 'Where' not found".
Here is the request :
using System.Linq;
[...]
var query = from item in listToQuery
where item.Site == _siteToQuery
&& item.ReportType == _recordTypeToQuery
&& item.Date == stringDate
select item;
Result = listToQuery.GetItems(query);
listToQuery and Result are two SPListItemCollection.
Why is where not recognized ?

It's normal. The SharePoint Object doesn't implement Linq query, so that's why you have this exception.
To Query a SharePoint List you need to use a CAML Query (with an object of type SPQuery )
you can find a lot of documentation on internet about "how to query a sharepoint list programmatically"
But if you still want to user LINQ on Sharepoint, you can use SPMetal

Related

dotnet core azure documentdb linq lambda query not running query on server

I'm running dotnet core and accessing documentdb.
When I try to run a query using a linq where clause it returns but it takes a long time and doesn't seem to filter on the server. I was able to resolve this by using the SqlQuerySpec to run the query and it now appears to run the query criteria on the server.
Is this a known issue or am I missing something?
The one that doesn't work:
var query = _client.CreateDocumentQuery<T>(documentCollection.DocumentsLink).Where(criteria);
return query.ToList();
criteria is of type
Func<T, bool> criteria
The one that does work:
var documentQuery = _client.CreateDocumentQuery<T>(UriFactory.CreateDocumentCollectionUri(_databaseName, collectionName), query).AsDocumentQuery();
List<T> results = new List<T>();
while (documentQuery.HasMoreResults)
{
results.AddRange(await documentQuery.ExecuteNextAsync<T>());
}
return results;
query is of type
SqlQuerySpec query
Is this a feature that is lagging behind in dotnet core's implementation of the documentdb sdk vs the standard .NET package?
The issue is that you are using Func<T, bool> for criteria. The one that you're using is for IEnumerable. By design IEnumerable will do in-memory filtering (client-side).
CreateDocumentQuery.Where() actually returns an IQueryable. You need to change your criteria type to Expression<Func<T, bool>>as this is what is expected by CreateDocumentQuery.
When you use an Expression, your LINQ expression is converted to the database specific SQL query and will be executed on the server.
Uri documentCollectionUri = UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId);
var query = client.CreateDocumentQuery<T>(documentCollectionUri)
.Where(predicate)
.AsDocumentQuery();
List<T> results = new List<T>();
while (documentQuery.HasMoreResults)
{
results.AddRange(await documentQuery.ExecuteNextAsync<T>());
}
return results;
Where predicate is Expression<Func<T, bool>>
One important thing to remember: You can only use those LINQ extentions that have an equivalent function in the DocumentDb's SQL language. For example, you can use Take() but you cannot use Skip(), you cannot use Array contains on specific nested fields, etc.
When I try to run a query using a linq where clause it returns but it takes a long time and doesn't seem to filter on the server.
If we capture the request when run var query = _client.CreateDocumentQuery<T>(documentCollection.DocumentsLink).Where(criteria);, we could find it performs a GET on the documents resource of a particular collection
GET https://{databaseaccount}.documents.azure.com/dbs/{db-id}/colls/{coll-id}/docs to get a list of documents under the collection, which does not really query and filter on DocumentDB server.
And Where method is used to filter a sequence of values based on a predicate, which happens on the client (not pass the search condition to DocumentDB server).

Querying DocumentDB using a property other than Id

I want to query my documents in my DocumentDB database. I want to use LINQ to handle the DocumentDB query and want to query for facebookUsername field.
If I use the code below for querying the standard Id field, it works fine but when I try to do it using facebookUsername field, I get a compile error that reads
"'Microsoft.Azure.Documents.Document' does not contain a definition
for 'facebookUsername' and no extension method 'facebookUsername'
accepting a first argument of type
'Microsoft.Azure.Documents.Document' could be found (are you missing a
using directive or an assembly reference?)"
Here's the code I'm currently using for querying by Id and this works. I just want to be able to query the facebookUsername field.
dynamic doc = (from f in client.CreateDocumentQuery(collection.DocumentsLink)
where f.Id == myId.ToString()
select f).AsEnumerable().FirstOrDefault();
How do I modify my code to query by facebookUsername field?
var families = from f in client.CreateDocumentQuery<Family>(colSelfLink)
where f.Address.City != "NY"
select f;
will give you a List where Family: { "Address" : {"City": "NY"} } }
if you don't have an object like Family, in my case, then you can't use Linq to evaluate queries on dynamic objects. You need to then use the SQL Query Grammar.
var families = client.CreateDocumentQuery<Family>(colSelfLink. "SELECT * FROM c WHERE field=value").AsEnumnerable();
should work.

CRM LINQ + Creating Dynamic where clause for anonymous types

var crm = new XrmDataContext("Crm");
var properties = from property in crm.awx_propertyawx_properties
orderby property.awx_name
select new {
awx_name = property.awx_name == null ? "no name" : property.awx_name
}
;
properties = properties.Where(a => a.awx_name.StartsWith("Sears Tower"));
I get the error "Cannot determine the attribute name" - what am I doing wrong here? I read in plenty of threads that this is perfectly okay to do. HELP!
I too spent quite a while trying to find a way of issuing dynamic where clauses against the CRM system.
I tried similar syntax above and also built a predicate builder. Both did not work.
In the end I had to take a 2 stage approach.
1. Pull a superset from CRM using static where clause into a collection
2. Query dynamically from my in memory collection using standard techniques.
I hate CRM.
Phil

Extension Method To Take A Dynamically Built Search Expression?

I think we are basically looking for a extension method that could take in an IQueryable and return an IQueryable based on an entire query statement and not just the where statement.
Example of what we would like for a Search Method:
IRepository<Person> repository = new Repository<Person>();
var results = repository.GetQuery().Include("Names").Search([dynamic linq here]);
We currently have where we build a dynamic linq statement inside the where method
IRepository<Person> repository = new Repository<Person>();
var results = repository.GetQuery().Include("Names").Where([dynamic linq here]);
The problem with that approach is that we want to do include SelectMany and Select on the actual dynamic linq query. You cannot use the SelectMany inside a Where method unless you are actually going into sub properties of sub properties. We would like to do something like the following dynamic linq statement.
SelectMany("Names").Where("LastName.Contains(#0)", "Smith").Select("Person")
We solved this issue without having to use a extension method. We were able to use a similar query that works inside a Where method.
So instead of...
SelectMany("Names").Where("LastName.Contains(#0)", "Smith").Select("Person")
We were able to get the same result with the following query that can be inside a Where method.
Where.("Names.Select(LastName).Contains(#0)", "Smith)
Then when just had to add a Contains Aggregate to the Dynamic Linq library.
http://blog.walteralmeida.com/2010/05/advanced-linq-dynamic-linq-library-add-support-for-contains-extension-.html
The SelectMany had sent us off on a wild goose chase!
Checkout this nuget package: NinjaNye.SearchExensions
It enables you to do something like the following:
var repository = new Repository<Person>();
var results = repository.GetQuery().Search(p => p.LastName, "Smith");
Connected to sql this will produce something smilar to the following:
SELECT [Extent1].[Id] AS [Id],
... [other properties],
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE ([Extent1].[LastName] LIKE N'%Smith%')
The query is built using expression trees so the result is clean.
Check out the source code here:
https://github.com/ninjanye/SearchExtensions/

LINQ syntax where string value is not null or empty

I'm trying to do a query like so...
query.Where(x => !string.IsNullOrEmpty(x.PropertyName));
but it fails...
so for now I have implemented the following, which works...
query.Where(x => (x.PropertyName ?? string.Empty) != string.Empty);
is there a better (more native?) way that LINQ handles this?
EDIT
apologize! didn't include the provider... This is using LINQ to SQL
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=367077
Problem Statement
It's possible to write LINQ to SQL that gets all rows that have either null or an empty string in a given field, but it's not possible to use string.IsNullOrEmpty to do it, even though many other string methods map to LINQ to SQL.
Proposed Solution
Allow string.IsNullOrEmpty in a LINQ to SQL where clause so that these two queries have the same result:
var fieldNullOrEmpty =
from item in db.SomeTable
where item.SomeField == null || item.SomeField.Equals(string.Empty)
select item;
var fieldNullOrEmpty2 =
from item in db.SomeTable
where string.IsNullOrEmpty(item.SomeField)
select item;
Other Reading:
1. DevArt
2. Dervalp.com
3. StackOverflow Post
This won't fail on Linq2Objects, but it will fail for Linq2SQL, so I am assuming that you are talking about the SQL provider or something similar.
The reason has to do with the way that the SQL provider handles your lambda expression. It doesn't take it as a function Func<P,T>, but an expression Expression<Func<P,T>>. It takes that expression tree and translates it so an actual SQL statement, which it sends off to the server.
The translator knows how to handle basic operators, but it doesn't know how to handle methods on objects. It doesn't know that IsNullOrEmpty(x) translates to return x == null || x == string.empty. That has to be done explicitly for the translation to SQL to take place.
This will work fine with Linq to Objects. However, some LINQ providers have difficulty running CLR methods as part of the query. This is expecially true of some database providers.
The problem is that the DB providers try to move and compile the LINQ query as a database query, to prevent pulling all of the objects across the wire. This is a good thing, but does occasionally restrict the flexibility in your predicates.
Unfortunately, without checking the provider documentation, it's difficult to always know exactly what will or will not be supported directly in the provider. It looks like your provider allows comparisons, but not the string check. I'd guess that, in your case, this is probably about as good of an approach as you can get. (It's really not that different from the IsNullOrEmpty check, other than creating the "string.Empty" instance for comparison, but that's minor.)
... 12 years ago :) But still, some one may found it helpful:
Often it is good to check white spaces too
query.Where(x => !string.IsNullOrWhiteSpace(x.PropertyName));
it will converted to sql as:
WHERE [x].[PropertyName] IS NOT NULL AND ((LTRIM(RTRIM([x].[PropertyName])) <> N'') OR [x].[PropertyName] IS NULL)
or other way:
query.Where(x => string.Compare(x.PropertyName," ") > 0);
will be converted to sql as:
WHERE [x].[PropertyName] > N' '
If you want to go change the type of the collection from nullable type IEnumerable<T?> to non-null type IEnumerable<T> you can use .OfType<T>().
.OfType<T>() will remove null values and return a list of the type T.
Example: If you have a list of nullable strings: List<string?> you can change the type of the list to string by using OfType<string() as in the below example:
List<string?> nullableStrings = new List<string?> { "test1", null, "test2" };
List<string> strings = nullableStrings.OfType<string>().ToList();
// strings now only contains { "test1", "test2" }
This will result in a list of strings only containing test1 and test2.

Resources