Showing posts with label VS 2010. Show all posts
Showing posts with label VS 2010. Show all posts

Tuesday, 16 October 2012

LINQ to SharePoint: linq query filter on multivalue lookup

Situation:
I have a SharePoint Foundation 2010 environment with a document library. One of the metadata on the documents is a multivalue lookup to a category list.
I used SPMetal to create entity classes for easy usage of linq to the different lists and libraries inside the SharePoint site.
Problem:
Inside a visual web part, I was trying to execute a linq query on the document library, filtering on a given category.
Example code:

QualityDataContext dc = new QualityDataContext(SPContext.Current.Web.Url);
// some other steps made
var mySelectedCat = dc.MyCategories.OrderBy(p => p.Title).Where(p => p.id == "CategoryOfInterestID")

var docs = dc.MyDocLib.OrderBy(p => p.Title).Where(p => p.Categories.Contains(mySelectedCat));

This goes wrong because in this situation linq is messing up with the "p.Categories" en the entity "mySelectedCat"

Solution:
I have searched a lot, without getting a right, easy solution. Some mentioned to use the 'old' "SPWeb, SPList, SPQuery and so on"-way. Others where trying to believe you that the sample above is working.
Sorry folks, it's not. The problem is that querying on the multivalue lookup just works after the data has been retrieved. So I uses the ToList() method to the 'docs' part, just before filtering. For performance reasons, I first get the whole list (I just needed the whole list) and then do the filtering on the moment I needed it.
So this results in the following piece of code that I am using to fill a tree view, grouped on main category and sub category with links to documents.
Note the 'ToList()' I am using, twice just straight in the beginning of the using section. This is doing the trick.

using (QualityDataContext dc = new QualityDataContext(SPContext.Current.Web.Url))
{
 var cats = dc.MyCategories.OrderBy(p => p.Title).ToList();
 var docs = dc.MyDocuments.OrderBy(p => p.Title).ToList();

 SPTreeView tv = new SPTreeView();

 var mainCat = cats.OrderBy(p => p.Category).GroupBy(p => p.Category);
 
 // Step through the main categories
 foreach (var item in mainCat)
 {
  TreeNode catNode = new TreeNode{ Text = item.Key, Value = item.Key };
  
  var subCats = cats.OrderBy(p => p.Title).Where(p => p.Category == item.Key);

  // Step through the sub categories
  foreach (var subCat in subCats)
  {
   TreeNode subCatnode = new TreeNode { Text = subCat.Title, Value = subCat.Id.ToString() };
   var subdocs = docs.Where(p => p.Categories.Contains(subCat));

   if (subdocs.Count() > 0)
   {
    foreach (var doc in subdocs)
    {
     string docUrl = doc.Path + "/" + doc.Naam;
     subCatnode.ChildNodes.Add(new TreeNode { Text = doc.Naam, ToolTip = doc.Title, NavigateUrl = docUrl, Target = "_blank" });
    }
    subCatnode.Collapse();
    catNode.ChildNodes.Add(subCatnode);
   }
  }
  tv.Nodes.Add(catNode);
 }
 this.Controls.Add(tv);

Thursday, 5 July 2012

Value does not fall within the expected range

Currently working on SharePoint and yep, running into strange problems and errors. A better name will be ShareProblems or SharePointless. However, just kidding a bit. But seriously, I run into the following situation:
Situation:
Running a webservice outside SharePoint which will receive data from a webform (on another server) in JSON format. The received data will be saved in a SharePoint list by using the client side object model. So far so good. The initial test where run by the administrator account (used for the installation and configuration of SharePoint). It worked fine. Because I have to run a workflow on 'new item created' on the SharePoint list, I needed a 'normal' account. The admin and service accounts are not allowed to start workflows. So, new AD account defined, gave the appropriate rights and voila... uh, not really.
Problem: 
Part of the code:

ListItemCreationInformation lici = new ListItemCreationInformation();
ListItem item = list.AddItem(lici);

item["Title"] = HttpUtility.UrlDecode(name);
item["Category"] = (categorie == "0") ? 15 : int.Parse(categorie);
item["Street"] = HttpUtility.UrlDecode(street);
item["Postal_x0020_Code"] = HttpUtility.UrlDecode(postalcode);

item.Update();
_clientContext.ExecuteQuery();


I got the return message: Value does not fall within the expected range.
The callstack was something like this:

at Microsoft.SharePoint.Client.ClientRequest.ProcessResponseStream(Stream responseStream) at Microsoft.SharePoint.Client.ClientRequest.ProcessResponse() at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery() at DnmWebServices.MessagingService.SendRtvRequest(String name, String category, String street, String postalcode) in c:\inetpub\wwwroot\DnmWebServices\App_Code\MessagingService.cs:line 128
Line 128 in my case points to the _clientContext.ExecuteQuery.
Solution(s):
It seems there can be several causes.
1). Use of invalid field name. You need to use the internal field name! However, that was not the case in my situation.
2). Change the List View Lookup Threshold value of the web application. Default value is 8, I changed it to 20 and big surprise: it worked! Thanks to this post.
Note: My item has some lookup fields some of which some have more than 8 items.
Little conclusion: So it seems that when using (one of) the system admin accounts, this list view lookup threshold is ignored in one way. By using non-system admin accounts, it can be a show stopper.
Steps to edit this value:

  • Go to Central Administration > Application Management > Manage web applications
  • Select the appropriate web application (in my case the SharePoint - 80)
  • In the ribbon bar, select General Settings > Resourse Throttling
  • Search for the List View Lookup Threshold and change the value to 20.

Tuesday, 22 March 2011

The query uses unsupported elements

I am using SPMetal for creating partial classes for accessing my SharePoint lists by code.
Today I was trying to run a Linq query in LinqPad on a SharePoint list (see here how to use LinqPad on SharePoint data). See query:
var q = from w in WorkItems
  where w.ShortUserID == "rob"
  where (((DateTime)(w.WorkDate)) >= firstDay 
     && ((DateTime)(w.WorkDate)) <= firstDay.AddDays(6))
  select new {w.Title, w.WorkDate, w.Hours, sprint = w.SprintItem.Title};
q.Dump();
Well, it's just an ordinary Linq query, but as always with SharePoint related programming, nothing goes well the first time. I got the following error message:
The query uses unsupported elements, such as references to more than one list, or the projection of a complete entity by using EntityRef/EntitySet
It has something to do with the 'sprint' information I needed. The 'SprintItem' is a property (Type of SprintItem object) of the WorkItem class. Somehow this will fail.
An explanation given by Paul Beck (see his blog):
ToList() method forces immediate query evaluation and returns the generic that contains the query result. As described in the MSDN article LINQ can't convert the LINQ to SharePoint into a CAML query so by using the ToList() method, the query is broken into 2 stages. This will apply to queries that use JOINS, UNIONS, and various other LINQ operators as described in the MSDN Unsupported LINQ queries article.
In his article he relates this problem with 'join'. However, I didn't use this keyword. Nevertheless his solution worked, I needed to put 'ToList()' right behind 'WorkItems' and the problem is solved. So the code will now looks like:
var q = from w in WorkItems.ToList()
  where w.ShortUserID == "rob"
  where (((DateTime)(w.WorkDate)) >= firstDay 
      && ((DateTime)(w.WorkDate)) <= firstDay.AddDays(6))
  select new {w.Title, w.WorkDate, w.Hours, sprint = w.SprintItem.Title};
q.Dump();

Thursday, 10 March 2011

LinqPad on SharePoint data

Linq to SharePoint is great! The SPMetal.exe is really easy to use (see here how to use it).
But I was struggling a bit to get the right Linq queries. So I thought, well let's use LinqPad. I ran into the following error message:
PropertyOrFieldNotInitializedException: The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
I searched for a solution, but I didn't find one. Today I figured out how to use LinqPad to query on SharePoint data, without facing these security-IIS-related issues.
On CodePlex you can find the LinqPad Data Context Driver for SharePoint created by a guy named 'theiwaz'. Creating a new connection in LinqPad, using this driver did the trick. Read the documentation how to install and setup the configuration (very easy!).

In my situation, I ran into a small problem. The documentation shows a screenshot with a sample code, using "C# Expression" a the language.
When I tried that, it failed. I got the following message:
String was not recognized as a valid Boolean
 Changing the language to "C# Statement(s)" did the trick for me. I only need to rewrite the code a little bit. But that's actually a great advantage, because it now looks like the code as I will use inside my VS2010 project.
var q = from prod in Products
    where prod.Customer.Title == "DNM"
    select  prod.Title;

q.Dump(1);

Wednesday, 2 March 2011

customerrors mode off not working on SharePoint 2010

During the developing of a custom field, I faced some errors, but the didn't work.
After some search, it seems that you have to do this trick on three locations. SharePoint 2010 has web.config files on the following locations:
  • C:\inetpub\wwwroot\wss\VirtualDirectories\80\
  • C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG\
  • C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS
On all these locations you can find a web.config file.
Change customerrors to:
<customErrors mode="Off" />
and the SaveMode tag (if available) to:
<SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="true">
as well as the compilation tag to:

<compilation batch="false" debug="true" optimizeCompilations="true">
This did the trick for me

Friday, 25 February 2011

Productivity Power Tools

Recently I found the Productivity Power Tools of Microsoft for Visual Studio. The extra functionality you get is very useful:
  • Find extension
  • Enhanced Scrollbar
  • Middle-Click Scrolling
  • Organize Import for VB.NET
  • Add Reference Support for Multi-Targeting
  • Options in HTML Cut/Copy
  • Solution Navigator (an enhanced Solution Explorer)
  • Tab Well UI
  • Searchable Add Reference Dialog
  • Tools Options Support
  • Quick Access (search for and execute common tasks within VS IDE)
  • Auto Brace Completion (Supports the following constructs: (), {}, [], <>, “”, and ‘’. This is really useful!)
  • Highlight current line
  • HTML Copy
  • Triple Click
  • Fix Mixed Tabs
  • CTRL+Click Go to definition
  • Align Assignments
  • Move Line Up/Down commands
  • Column Guides
  • Colorized Parameter Help
So, it's quit a list and beside of this, it's FREE!. See the web site (above) of these tools to get more information and to download these tools.