LINQ to SharePoint の仕組みを理解する
はじめに
SharePoint 2010 から LINQ to SharePoint という機能が追加されました。これまでの SPQuery
によるクエリ検索をより簡単にする仕組みで、Entity Framework を使ったことのある開発者であれば、ほとんど違和感なく使うことができます。SPQuery
で使われる CAML は開発者にとって直観的ではなかったので、LINQ to SharePoint によって SharePoint 開発がずっと簡単になります。
LINQ to SharePoint を使うためには、SPMetal
というツールでコードを自動生成します。日本語環境だと、コードに日本語が混ざってしまうのと、不要なリストのエンティティ クラスまで作ってしまうのが困りものですが、普通に使うだけなら十分です。今回は、SPMetal
で自動生成されるコードを参考に、ゼロからコードを書いてみます。
サンプル コード
実行手順
事前準備
サンプルとして テスト という名前で空のカスタム リストを作成します。
コンテキスト クラス
Entity Framework に DBContext
クラスがあるように、LINQ to SharePoint にも DataContext
クラスが存在します。コンストラクタでは接続文字列を受け取る代わりにサイトの URL を受け取ります。リストの取得は GetList
メソッドで行いますので、これをプロパティとしてラップします。[1]
public class SharePointDataContext : DataContext
{
public EntityList<Test> Tests
{
get { return this.GetList<Test>("テスト"); }
}
public SharePointDataContext(string url)
: base(url) { }
}
エンティティ クラス
SharePoint にはコンテンツ タイプという概念があり、LINQ to SharePoint ではこれをクラスの継承で表現します。すべてのコンテンツ タイプはアイテムから派生しますので、まずは Item
クラスを作成します。
ContentTypeAttribute
属性でコンテンツ タイプの名前と ID を指定します。ここの名前がサイトの定義と一致していれば、クラス名は任意で構いません。
[ContentType(Name = "アイテム", Id = "0x01")]
public class Item : ITrackEntityState, ITrackOriginalValues, INotifyPropertyChanged, INotifyPropertyChanging { ... }
アイテムを取得するだけなら必要ないのですが、アイテムを更新するためには、4 つのインターフェイスを継承する必要があります。それぞれのインターフェイスは以下のような役割を持ちます。
-
ITrackEntityState
インターフェイスはエンティティの状態管理に関するプロパティを定義します。 -
ITrackOriginalValues
インターフェイスは変更前の値を保持するディクショナリを定義します。 -
INotifyPropertyChanged
インターフェイスとINotifyPropertyChanging
インターフェイスはプロパティの変更を通知するイベントを定義します。
リストの列は ColumnAttribute
属性でマッピングします。Storage
にはプロパティ名ではなくフィールド名を指定する必要があります。プロパティの変更を通知するのを忘れずに。Title
列の例ですが、ID
や Version
も同様に定義します。
private string title;
[Column(Name = "Title", Storage = "title", Required = true, FieldType = "Text")]
public virtual string Title
{
get { return this.title; }
set {
if (this.title != value)
{
this.OnPropertyChanging("Title", this.Title);
this.title = value;
this.OnPropertyChanged("Title");
}
}
}
OnPropertyChanged
はおなじみの実装で問題ありませんが、OnPropertyChanging
はイベントの発生前に変更前の値を保持するように追加の処理を行います。
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangingEventHandler PropertyChanging;
protected void OnPropertyChanging(string propertyName, object value)
{
if (this.OriginalValues.ContainsKey(propertyName) != true)
{
this.OriginalValues.Add(propertyName, value);
}
var handler = this.PropertyChanging;
if (handler != null)
{
handler.Invoke(this, new PropertyChangingEventArgs(propertyName));
}
}
最後に Item
クラスを継承した Test
クラスを作成します。これが実際のリストの定義になります。今回は列を追加していないのでそのままですが、列を追加した場合は、Item
クラスの例と同様に設定できます。
[ContentTypeAttribute(Name = "テスト", Id = "0x01")]
public class Test : Item { ... }
実行結果
サンプル プログラムを作成します。
private static void Main(string[] args)
{
using (var context = new SharePointDataContext("http://sharepoint.examle.com"))
{
var item1 = new Test() { Title = "タイトル 1" };
var item2 = new Test() { Title = "タイトル 2" };
var item3 = new Test() { Title = "タイトル 3" };
context.Tests.InsertOnSubmit(item1);
context.Tests.InsertOnSubmit(item2);
context.Tests.InsertOnSubmit(item3);
context.SubmitChanges();
foreach (var item in context.Tests)
{
Console.WriteLine("{0}:{1}", item.ID, item.Title);
}
Console.ReadLine();
}
}
実行すると以下のように表示されます。
1:タイトル 1
2:タイトル 2
3:タイトル 3
-
リスト名の指定が表示名だけで URL や内部名は指定できないようです。 ↩︎
Discussion