Showing posts with label LINQ. Show all posts
Showing posts with label LINQ. Show all posts

Tuesday, February 1, 2011

Customize SPMetal Generated Code for SharePoint to LINQ

A common question that has come up with SharePoint 2010 developers. If they are using the SPMetal tool to generate entities (or class definitions) for objects in SharePoint, can they modify the generated code? The first response someone may say is no; that is not possible. The reason being is when you rerun the SPMetal command and then replace the new generated code overtop your existing code, you will lose your changes.

Well there is a solution and is it extremely simple. I actually got the idea from all the coding experiences I had with building customizations into RIA Services with Silverlight. All the SPMetal tool is doing is generating Proxy code and notice that all of the code is generated as partial classes!!! Now the sky is the limit.

So in the example below, here is a custom content type I created called Anonymous Comment. Below is the generated code and you can see it is a partial class. Now all you need to do is add another partial class to your project called, AnonymousComment and add in custom methods. When you use the AnonymousComment class in some other custom code it will be treated as one class definition.

Another neat thing you can is see there are partial methods for OnLoaded, OnValidate and OnCreated. You can extend those methods if you want and they will be called by the framework. One unfortunate thing you cannot do is modify the behavior of the getter and setter properties, but you can handle that in your custom partial class.

/// <summary>
/// The item that will capture an anonymous comment.
/// </summary>
[Microsoft.SharePoint.Linq.ContentTypeAttribute(Name="Anonymous Comment", Id="0x0100E3A8FCEBECB140D2812D4F3DE177EFEC")]
public partial class AnonymousComment : Item {

private string _comment;

private System.Nullable<System.DateTime> _created;

private string _response;

private System.Nullable<System.DateTime> _responseDate;

private System.Nullable<Category0> _category;

private System.Nullable<Status> _status;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate();
partial void OnCreated();
#endregion

public AnonymousComment() {
this.OnCreated();
}

[Microsoft.SharePoint.Linq.ColumnAttribute(Name="AnonymousComment", Storage="_comment", FieldType="Note")]
public string Comment {
get {
return this._comment;
}
set {
if ((value != this._comment)) {
this.OnPropertyChanging("Comment", this._comment);
this._comment = value;
this.OnPropertyChanged("Comment");
}
}
}

[Microsoft.SharePoint.Linq.ColumnAttribute(Name="Created", Storage="_created", ReadOnly=true, FieldType="DateTime")]
public System.Nullable<System.DateTime> Created {
get {
return this._created;
}
set {
if ((value != this._created)) {
this.OnPropertyChanging("Created", this._created);
this._created = value;
this.OnPropertyChanged("Created");
}
}
}

[Microsoft.SharePoint.Linq.ColumnAttribute(Name="AnonymousCommentResponse", Storage="_response", FieldType="Note")]
public string Response {
get {
return this._response;
}
set {
if ((value != this._response)) {
this.OnPropertyChanging("Response", this._response);
this._response = value;
this.OnPropertyChanged("Response");
}
}
}

[Microsoft.SharePoint.Linq.ColumnAttribute(Name="AnonymousCommentResponseDate", Storage="_responseDate", FieldType="DateTime")]
public System.Nullable<System.DateTime> ResponseDate {
get {
return this._responseDate;
}
set {
if ((value != this._responseDate)) {
this.OnPropertyChanging("ResponseDate", this._responseDate);
this._responseDate = value;
this.OnPropertyChanged("ResponseDate");
}
}
}

[Microsoft.SharePoint.Linq.ColumnAttribute(Name="AnonymousCommentCategory", Storage="_category", FieldType="Choice")]
public System.Nullable<Category0> Category {
get {
return this._category;
}
set {
if ((value != this._category)) {
this.OnPropertyChanging("Category", this._category);
this._category = value;
this.OnPropertyChanged("Category");
}
}
}

[Microsoft.SharePoint.Linq.ColumnAttribute(Name="AnonymousCommentStatus", Storage="_status", FieldType="Choice")]
public System.Nullable<Status> Status {
get {
return this._status;
}
set {
if ((value != this._status)) {
this.OnPropertyChanging("Status", this._status);
this._status = value;
this.OnPropertyChanged("Status");
}
}
}
}

Saturday, July 10, 2010

SharePoint LINQ Query Error

Issue

If you are using the new Microsoft.SharePoint.Linq API for SharePoint 2010 web parts you may run into the following problem. Here is some code:

TeamSiteDataContext context = new TeamSiteDataContext(SPContext.Current.Web.Url);

TeamSiteDataContext context = new TeamSiteDataContext(SPContext.Current.Web.Url);
EntityList<Task> tasks = context.GetList<Task>("Tasks");

DateTime? queryDate = new DateTime(2010, 7, 16);

var results = from tsk in tasks
where tsk.DueDate == queryDate
select tsk;

spGridView.DataSource = results;
spGridView.DataBind();

All I am doing is running a LINQ query for tasks. This code will give the following error:

One or more field types are not installed properly. Go to the list settings page to delete these fields.

Solution

While researching this, I found that if I got rid of the DueDate, the error would go away but that was not an acceptable solution. I did some research on and could not find anything on SharePoint 2010, as this was an issue you could have when writing SPQuery in older versions of SharePoint.

The ultimate solution was to change the second line to the following:

EntityList<TasksTask> tasks = context.GetList<TasksTask>("Tasks");

The reason is I used SPMetal to generate the proxy to SharePoint 2010. In the generated class there will be a Task and TasksTask classes. The Task maps to the generic content type while the TasksTask maps to the content type of the task list. When I used the class for the content type mapped to the list I was querying against, the error went away.