次の方法で共有


エンティティ クラス

最終更新日: 2010年3月9日

適用対象: SharePoint Foundation 2010

この記事の内容
SPMetal の使用
データ コンテキスト クラス
リスト、コンテンツ タイプ、およびリスト項目

このトピックでは、LINQ to SharePoint プロバイダーのエンティティ クラスについて説明します。これらのクラスは、オブジェクト指向の C# または Microsoft Visual Basic によるコードと Microsoft SharePoint Foundation のコンテンツ データベースのリレーショナル テーブル構造の間で、ライトウェイトなオブジェクトリレーショナル インターフェイスを提供します。また、object change tracking システムの基盤も提供します。

このオブジェクトリレーショナル インターフェイスを使うと、LINQ クエリ内でオブジェクト指向コードを使用でき、標準の SharePoint Foundation オブジェクト モデルとは別に、データベース エンティティを参照するオブジェクト指向コードからリスト項目の作成、削除、および更新を行えます。さらに、オブジェクトリレーショナル フレームワークを適切に設定した後、このフレームワークのライトウェイトな遅延読み込みが標準の SharePoint Foundation オブジェクト モデルよりも有利に働くような状況で、これをオブジェクト指向のビジネス ロジックとして使うこともできます。これらのエンティティ クラスを標準のオブジェクト モデルの代わりに使用すると、foreach ループで LINQ クエリの結果を反復処理するときのように同じエンティティ クラスを使用している LINQ クエリとコンテンツ参照とが近接するとき、コードの可読性が改善されることもあります。

SPMetal の使用

この記事で説明するクラスの作成は非常に単調で、間違いを起こしやすいので、SharePoint Foundation には SPMetal というコマンド ライン ツールが用意されており、これでクラスとプロパティの宣言を生成できます。このツールは、コンテンツ タイプの定義と、ターゲット SharePoint Foundation Web サイトのリストで使用するリスト スキーマを読み込み、それらに基づいて属性修飾を含むエンティティ クラスを生成します。このツールは SharePoint Foundation に同梱され、通常は、フォルダー %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\BIN に入っています。このツールを使用することをお勧めします。

SPMetal によるコードの生成はカスタマイズできます。さらに、このツールで生成されるコードはすべて partial (Visual Basic の場合は Partial) とマークされるので、別に用意したコード ファイル内でそれらにメンバーを追加できます。SPMetal によるエンティティ クラスの生成を再度行う必要がある場合も、生成されたファイルだけが上書きされ、別に用意したカスタム メンバーを含むファイルは上書きされません。SPMetal の使用方法については、「[方法] SPMetal を使用する」を参照してください。

ヒントヒント

この記事で説明するクラスについては、その宣言をすべて SPMetal によって生成することをお勧めします。この記事のコード例は、現実のコードにそのままコピーして使うことを想定しておらず、SPMetal で生成されるコードそのものとも完全には一致しません。いずれも、本質と関係ないコードは省いて簡略化してあります。特に、オブジェクト変更履歴システムに関係するコードは、これらの例からすべて省いてあります。これをサポートするシステムとコードの詳細については、「オブジェクト変更追跡とオプティミスティック同時実行制御」を参照してください。また、このトピックで説明するクラスおよびプロパティ宣言の属性修飾は現実に必要とされるものよりも全般的に単純化されており、完全に省略された属性もあります。属性とその用法の詳細については、以下のクラス (およびそのメンバー) に関するリファレンス トピックを参照してください。

データ コンテキスト クラス

エンティティ クラスの階層の最上位に、Web サイトのコンテンツを表す DataContext クラスがあります。DataContext オブジェクトをインスタンス化するには、そのコンストラクターに対して、モデル化するデータがある Web サイトの URL を渡し、その GetList<T>(String) メソッドを呼び出して、特定のリストへの参照を取得します。次に例を示します。

DataContext teamData = new DataContext("http://DeptServer/TeamSite")
EntityList<Announcment> teamAnns = teamData.GetList<Announcement>("Announcements");

"Announcement" というコンテンツ タイプ (以下を参照) を表すクラスが宣言してあるものと仮定すると、次のようにして teamAnns に対するクエリを実行できます。

var excitingAnns = from ann in teamAnns
                   where ann.Title.EndsWith("!")
                   select ann;

DataContext を継承し、かつ Web サイトのリストごとに 1 つのプロパティを持つようにクラスを宣言すれば、通常、呼び出し元のコードをもっと読みやすく、よりオブジェクト指向的にできます。そのような宣言の例を次に示します。

public partial class TeamSite : DataContext 
{
    public TeamSite(string requestUrl) : 
        base(requestUrl) { }

    [List(Name="Announcements")]
    public EntityList<Announcement> Announcements 
    {
        get { return this.GetList<Announcement>("Announcements"); }
    }

}

注意

ListAttribute は、DataContext オブジェクトが表す Web サイトにある特定のリストを表すプロパティを識別します。

この宣言を適切に行った後に、呼び出し元のコードから GetList<T>(String) メソッドを明示的に呼び出す必要はありません。これは例を見れば自明です。

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var excitingAnns = from ann in teamData.Announcements
                   where ann.Title.EndsWith("!")
                   select ann;
重要重要

TeamSite クラスのコンストラクターは、Announcements リストの全体を読み込むことはしません。EntityList<TEntity> クラスは遅延読み込みをサポートしています。このタイプのオブジェクトは、その後のコードで明示的に参照されるまでは読み込まれません。

SPMetal ツールでは、常に、DataContext から派生したクラスが生成されます。そこでどのリストをモデル化するかを構成できます。既定では、Web サイトにある非表示でないすべてのリストについてプロパティが宣言されます。

注意

当然、リストを表さないメソッド、イベント、フィールド、プロパティなどを DataContext 派生クラスに追加することもできます。こうしたメンバーを追加する場合には、SPMetal によって生成されたファイルとは別のコード ファイルを用意してそこに宣言を記述してください。これで、SPMetal によるコードの生成を再度行う必要がある場合も自分で作成したコードが上書きされなくなります。

リスト、コンテンツ タイプ、およびリスト項目

LINQ to SharePoint を使用するソリューションでは、SharePoint のリスト、コンテンツ タイプ、およびリスト項目をエンティティ クラスによって表す必要があります。

EntityList<TEntity> クラスは、SharePoint Foundation リストを表します。タイプ変数 TEntity は、リスト項目の種類、すなわちコンテンツ タイプです。EntityList<TEntity> タイプのプロパティには、それが表すリストと同じ名前 ("Announcements"、"Calendar" など) を付けます。TEntity には、通常、それと同じ名前の単数形 ("Announcement" など) を付けますが、リストの名前そのものが単数形の場合は、別の名前を使うこともあります。たとえば、Calendar リストを表すクラスのタイプに "CalendarEvent" という名前を使用します。カスタム リストの場合は、リストの名前と名前 "Item" を連結してタイプの名前を作成します。たとえば、カスタム "Books" リストにはタイプ "BooksItem" という名前が付けられます。EntityList<TEntity> クラスはシールされていて、パブリック コンストラクターを持っていません。特定の TEntity について EntityList<TEntity> タイプのプロパティを宣言する例については、「データ コンテキスト クラス」セクションを参照してください。

コンテンツ タイプそのものもクラスとして宣言する必要があります。次の例に示すように、宣言を ContentTypeAttribute で修飾します (短縮形として "ContentType" を使用できます)。

[ContentType(Name="Announcement" Id="Ox0104")]
public partial class Announcement
{

}

クエリやその他のコードから明示的に参照するフィールド (またはプロパティ) については、コンテンツ タイプのクラス定義内で、リストの各フィールド (およびメタデータ プロパティ) を表すとき、あるパブリック プロパティを使用する必要があります。このようなクラスは他のプロパティも持つことがあるので、次の例に示すように、フィールド (およびメタデータ プロパティ) を表すクラスを [ColumnAttribute] 修飾で区別します (短縮形として [Column] を使用できます)。

[ContentType(Name="Customer")]
public partial class Customer : Item
{
    [Column]
    public Int32 CustomerId { get; set; }

    [Column]
    public String Name { get; set; }
}
注意注意

エンティティ クラスの生成後にリスト スキーマを変更すると、それらのエンティティ クラスを使用しているソリューションが失敗する場合があります。

コンテンツ タイプの継承

コンテンツ タイプのクラスでは、それが表す実際のコンテンツ タイプの継承リレーションシップをミラーリングできます。SharePoint Foundation における基本コンテンツ タイプは Item と呼ばれています。これはリスト項目に必ず存在する基本的なフィールド (Title など) を提供します (これらの基本的なフィールドの中には、IDVersion など、SharePoint Foundation の標準リスト ビューにおいて既定で非表示にされるものがあります)。以下に、Item コンテンツ タイプのクラス宣言を簡略化したものを示します。

[ContentType(Name="Item")]
public partial class Item
{
    private Nullable<Int32> _id;
    private Nullable<Int32> _version;
    private String _title;

    [Column]
    public Nullable<Int32> Id { get; set; }

    [Column]
    public Nullable<Int32> Version { get; set; }

    [Column]
    public String Title { get; set; }

  // Other member declarations omitted for readability.
}

その他のすべてのコンテンツ タイプのクラスは、Item から派生します。そのため、それらのクラスでは、継承するプロパティを明示的に宣言する必要はありません。

リスト間のリレーションシップと遅延読み込み

このオブジェクトリレーショナル インフラストラクチャでは、リスト間に永続的なリレーションシップを設定できます。そのリレーションを表すために使用する AssociationAttributeEntityRef<TEntity> および EntitySet<TEntity> クラスでは、EntityList<TEntity> のように、それらが表すエンティティの読み込みが、実行時にエンティティが初めて実際にアクセスされるまで延期されます (リレーションシップを表すとき、LookupList<T> オブジェクトを関係させることもできます)。

重要重要

SharePoint Foundation では、一方のリストにもう一方のリスト内の列に対するルックアップの列がある場合にだけ、その 2 つのリストを関連付けることができます。

エンティティ参照

EntityRef<TEntity> クラスは、各種のリストに含まれるリスト項目間の多対一または一対一のリレーションシップのシングルトン側でのリスト項目を表すと共にその遅延読み込みを提供します。たとえば、チームの各メンバーに割り当てられたセキュリティ コードが、セキュリティ上の理由からチーム メンバー リストとは別のリストに格納されているものと仮定します。また、TeamMember クラスは Team Members リスト上のチームのタイプを表し、SecurityCode クラスは Security Codes リストの項目のタイプを表します。セキュリティ コードはチームのメンバーごとに 1 つしか存在しないので、TeamMember クラスで、Security Codes リスト内の項目を表す EntityRef<TEntity> タイプ (ここで、TEntity は SecurityCode) の private フィールドを宣言します。さらに TeamMember クラスで、プライベート フィールドをラップする SecurityCode タイプの public プロパティも宣言します。AssociationAttribute で修飾するのは、このプロパティです。TeamMember タイプのオブジェクトをインスタンス化したとき、SecurityCode 値はすぐには読み込まれません。これが読み込まれるのは、その後のコードで参照される場合で、その場合に限って読み込まれます。

以下に、TeamMember クラス宣言の関連部分の例を示します。この例では、次の点に注意してください。

  • 2 つのテーブルの間のリレーションシップは、AssociationAttribute 修飾で宣言されます (EntityRef<TEntity> クラスを使用することで遅延読み込みが提供されますが、それだけでリストのリレーションシップが設定されるわけではありません)。

  • AssociationAttributeMultivalueType プロパティは、関連付けられたリスト内に、各項目に対応する項目が 1 つしか存在しないのか、それとも複数存在するのかを指定します。

  • AssociationAttributeList プロパティは、関連付けられたリストの大文字と小文字を区別した名前を指定します。

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntityRef<SecurityCode> memberSecurityCode;

    [Association(List = "SecurityCodes", MultiValueType = AssociationType.Single)]
    public SecurityCode MemberSecurityCode
    {
        get { return memberSecurityCode.GetEntity(); }
        set { memberSecurityCode.SetEntity(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "SecurityCode")]
public class SecurityCode
{
    [Column]
    public String Value { get; set; }

    // Declarations of other members suppressed for readability.
}

注意

MemberSecurityCode プロパティの get アクセサーと set アクセサーでは、プロパティとそれがラップするフィールドの間でタイプが実際には異なるので、よく知られているアクセサー コード ("return securityCode" および "securityCode=value") の代わりに GetEntity() メソッドと SetEntity(TEntity) メソッドが使用されます。この 2 つのメソッドは、EntityRef<TEntity> オブジェクトにアクセスして、そこでラップされている SecurityCode オブジェクトを処理します。

これで、オブジェクト指向のドット記法を使用してチーム メンバーのセキュリティ コードにアクセスでき、関連付けがクエリ内で 2 つのリストの永続的な結合と同じように機能します。たとえば、次のクエリで member は Team Members リスト内の項目ですが、MemberSecurityCodeSecurity Codes リスト内の項目への参照となります。

var result = from member in teamMembers
             where member.MemberSecurityCode.Value.Contains("guest")
             select member;

このリレーションシップは、ルックアップ ソース コンテンツ タイプを表すクラス内と、ターゲット コンテンツ タイプを表すクラス内のどちらでも定義できます。Team Members リストと Security Codes リストの間のリレーションシップを定義するには、次のように SecurityCode クラスのプロパティを使用します。

[ContentType(Name = "SecurityCode")]
public partial class SecurityCode
{
    [Column]
    public String Value { get; set; }

    private EntityRef<TeamMember> teamMember;

    [Association(List = "TeamMembers", MultiValueType = AssociationType.Single)]
    public TeamMember TeamMember
    {
        get { return this.teamMember.GetEntity(); }
        set { this.teamMember.SetEntity(value); }
    }
    // Other member declarations suppressed for readability.
}

リレーションシップをターゲット クラス内でこのように宣言すると、呼び出し元のコード内で逆引きのルックアップを行えるようになります。リレーションシップを両方のクラスで宣言すれば、どちらの方向でもルックアップを行えます。逆引きのルックアップについては、以下の「逆引きのルックアップ」を参照してください。

エンティティ セット

EntitySet<TEntity> クラスは、各種のリストに含まれるリスト項目間の多対一または多対多のリレーションシップの "多" 側でのリスト項目を表すと共にその遅延読み込みを提供します。たとえば、チームの各メンバーが複数のプロジェクトに割り当てられ、各プロジェクトに複数のチーム メンバーが割り当てられているものと仮定します。これは多対多のリレーションシップです。TeamMember クラスは Team Members リスト上の項目のタイプを表し、Project クラスは Projects リストの項目のタイプを表します。TeamMember クラスで、Projects リスト内の 1 つまたは複数の項目を表す EntitySet<TEntity> タイプ (ここで、TEntity は Project) の private フィールドを宣言します。このフィールドを AssignedProjects という名前の publicEntitySet<Project> プロパティでラップします。TeamMember タイプのオブジェクトをインスタンス化したとき、この AssignedProjects プロパティによって参照されるオブジェクトはすぐには読み込まれません。これが読み込まれるのは、その後のコードで参照される場合で、その場合に限って読み込まれます。

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntitySet<Project> assignedProjects;

    [Association(List="Projects", MultiValueType=AssociationType.Multi)]
    public EntitySet<Project> AssignedProjects
    {
        get { return this.assignedProjects; }
        set { this.assignedProjects.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

注意

上のコード例のように、Project クラスを表すコードには、Title 列を表す Title プロパティの宣言があります。これは読みやすくするために簡略化してあります。現実のコードでは、Project クラスは、SharePoint Foundation の基本コンテンツ タイプを表す Item クラスを継承します。その場合、Title プロパティは Item クラスの定義内で宣言されるので、この Project クラスの定義にはありません。

これらの宣言を適切に行った後、次の例のようにクエリを実行して、特定のプロジェクトに割り当てられたチーム メンバーを照会できます。

Project fiscalPlan = new Project() { Title="Fiscal year planning." };

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var filteredTeamMembers = from member in teamData.TeamMembers
                          where member.AssignedProjects.Contains(fiscalPlan) 
                          select member;

EntityRef<TEntity> の例では、関連する 2 つのリストのコンテンツ タイプを表す 2 つのクラスのどちらを使用してもリレーションシップを定義できます。次に、同じ Team MembersProjects リレーションを Project クラス内で宣言する例を示します。

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    private EntitySet<TeamMember> assignedTeamMembers;

    [Association(List="Team Members", MultivalueType=AssociationType.Multi)]
    public EntitySet<TeamMember> AssignedTeamMembers
    {
        get { return this.assignedTeamMembers; }
        set { this.assignedTeamMembers.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

両方のクラスでリレーションシップを宣言できます。詳細については、以下の「逆引きのルックアップ」を参照してください。

一対多と多対一のリレーション

「エンティティ参照」では、リスト間に一対一のリレーションを設定するコードの例を示し、「エンティティ セット」では、多対多のリレーションを設定するコードの例を示しました。一対多と多対一のリレーションを表すこともできます。「エンティティ セット」の例を引き続き使用し、各チーム メンバーが複数のプロジェクトに割り当てられているだけでなく、リーダーも複数のプロジェクトに割り当てられているものと仮定します。ただし、各プロジェクトのリーダーは 1 人だけです。Team Members リストと Projects リストの間のリーダーシップの関係は一対多のリレーションです。このリレーションは、次の例に示すように、TeamMember クラスの EntitySet<TEntity> メンバーと、Projects クラスの EntityRef<TEntity> メンバーを使用して表すことができます。

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntitySet<Project> projectsLedBy;

    [Association(List="Projects", MultivalueType=AssociationType.Multi)]
    public EntitySet<Project> ProjectsLedBy
    {
        get { return this.projectsLedBy; }
        set { this.projectsLedBy.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    private EntityRef<TeamMember> lead;

    [Association(List = "TeamMembers", MultiValueType = AssociationType.Single)]
    public TeamMember Lead
    {
        get { return this.lead.GetEntity(); }
        set { this.lead.SetEntity(value); }
    }

    // Declarations of other members suppressed for readability.
}

複数の値を許すルックアップ リスト

LookupList<T> クラスは、複数の値を取ることができるルックアップ フィールドの現在の値を表します。したがって、これはルックアップ リスト リレーションシップのターゲット リストのターゲット列で見つかった値のサブセットです。現在のリスト項目オブジェクト内でルックアップした値の列を保持する LookupList<T> タイプのプライベート フィールドをコンテンツ タイプ クラスに設けることができます。

EntitySet<TEntity> プロパティでルックアップ列を表すことができるので、通常、このフィールドを設ける必要はありません。しかし、LookupList<T>EntitySet<TEntity> では読み込みの動作に違いがあるので、このフィールドを設けることもあります。2 つのコンテンツ タイプ クラス A と B があり、A は LookupList<T> フィールドを使用してルックアップ列を表し、B は EntitySet<TEntity> を使用するものと仮定します。これ以外の点で A と B に違いはありません。どちらの場合も、クエリを列挙するとき (通常、foreach ループ内で行う)、特に、ループがそのコンテンツ タイプの特定のリスト項目に達したとき、そのリスト項目を表すオブジェクトのプロパティを設定するためにデータベースに対してクエリを実行します。タイプ A のオブジェクトの場合は、LookupList<T> フィールドにすぐにルックアップ列の値が設定されます。その後、foreach ループ内で、このフィールド (または、それをラップしたプロパティ) を参照するとき、データベースに対して 2 回目のクエリを実行する必要はありません。ただし、EntitySet<TEntity> タイプのオブジェクトについては、読み込みが遅延されるので、foreach ループがタイプ B の特定のオブジェクトに達したとき、EntitySet<TEntity> プロパティにターゲット リスト内の項目がすぐには設定されません。実際、ループ本体でプロパティが初めて参照されるまでは、読み込みは行われません。その参照が行われたとき、データベースに対して 2 回目のクエリを実行して、プロパティに値を設定する必要があります。

以下に、EntitySet<TEntity> プロパティを呼び出す例を示します。このコードは「エンティティ セット」で説明したものです。この例では、Team Members リストの AssignedProjects フィールドを Projects リストの Title フィールドに対するルックアップ フィールドとして構成し、そこで複数の値を許すように構成しています。

Project fiscalPlan = new Project() { Title="Fiscal year planning." };

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var filteredTeamMembers = from member in teamData.TeamMembers
                          where member.AssignedProjects.Contains(fiscalPlan) 
                          select member;

EntitySet<TEntity> は遅延読み込みを使用するので、TeamMember.AssignedProjects プロパティの値を、それが参照されるたびにコンテンツ データベースから取得する必要があります。LookupList<T> オブジェクトはすぐに読み込みを行うので、LookupList<T> フィールドをラップした IList<T> プロパティを呼び出すコードは、EntitySet<TEntity> プロパティを呼び出すコードよりも高速で実行されます。

引き続き同じ例を使用し、TeamMember クラスで、AssignedProjects フィールドの値を表す LookupList<T> タイプ (ここで、T は String) の private フィールドを宣言するものと仮定します。その値は、Projects リストのルックアップ ターゲット列 (Title) から取得されます。慣例により、このプライベート フィールドの名前には、ルックアップ列の名前と、値を取り出すターゲット列の名前 (複数形) を連結したものを使用し、名前を構成する最初の単語以外の各単語の最初の文字を大文字で表記します (キャメル ケース) 。この例のフィールドは assignedProjectsTitles となります。このフィールドを IList<String> タイプのパブリック プロパティでラップします。慣例により、このプロパティの名前には、フィールドの名前を使用し、名前を構成する各単語の最初の文字を大文字で表記します (タイトル ケース)。この例のプロパティは AssignedProjectsTitles となります。

注意

ルックアップ フィールドで複数の値を許すので、IList<T> プロパティの名前と LookupList<T> フィールドの名前は複数形で表記されます。1 つの値しか許さないルックアップ フィールドを表すとき、LookupList<T> クラスの名前は使われません。

以上で、TeamMember クラスに、Projects リストとのリレーションシップが宣言され、Assigned Projects リスト項目フィールドの値を参照する AssignedProjectsTitles プロパティが設けられました。次に、この 2 つをつなぐものが必要です。これは AssignedProjectsTitles プロパティを ColumnAttribute で修飾することによって実現されます。次の 4 つのプロパティを設定します。

  • Name="Assigned Projects" - 値が AssignedProjectsTitles プロパティで表される列を指定する。

  • FieldType="Lookup" - Name プロパティで識別されるフィールドが SharePoint Foundation の Lookup タイプであることを宣言する。

  • IsLookupValue=true – フィールドがルックアップ フィールドであることを宣言する。

  • LookupDisplayColumn="Title" - ターゲット リストのターゲット列を指定する。

以下のコードは、EntitySet<TEntity> プロパティと、LookupList<T> フィールドをラップする IList<T> プロパティの両方を使用してルックアップ リレーションをサポートするために必要な宣言を示しています。

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    [Column]
    public Int32 MemberID { get; set; }

    private EntitySet<Project> assignedProjects;

    private LookupList<String> assignedProjectsTitles;

    [Association(List="Projects", MultiValueType=Multi)]
    public EntitySet<Project> AssignedProjects
    {
        get { return this.assignedProjects; }
        set { this.assignedProjects.Assign(value); }
    }

    [Column Name="Assigned Projects", FieldType="Lookup", IsLookupValue="true", LookupDisplayColumn="Title"]
    public IList<String> AssignedProjectsTitles 
    {
        get { return this.assignedProjectsTitles; }
        set { this.assignedProjectsTitles.Assign(value); }
    }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

これらの宣言を適切に行った後、次の方法で前述の高速版のクエリを実行できます。

TeamSite teamData = new TeamSite("http://DeptServer/TeamSite");

var filteredTeamMembers = from member in teamData.TeamMembers
                          where member.AssignedProjectsTitles.Contains("Fiscal year planning.") 
                          select member;

注意

ルックアップ列の指すターゲット リスト自体が SPMetal 生成コードで表されないとき (たとえば、ターゲット リストが非表示のときや、SPMetal の構成ファイルでコード生成の対象から除外されているとき)、SPMetal では、LookupList<T> だけが生成されます。詳細については、「パラメーター XML ファイルを使用して SPMetal 既定をオーバーライドする」を参照してください。

特殊な "ID" LookupList オブジェクト

Lookup タイプのフィールドの値は、値の設定後、id;#display_value という形式になります。ここで、display_value は、ターゲット リストのターゲット列から取得した値で、id は、値が選択されたターゲット リスト内のリスト項目の ID です。これは SharePoint Foundation の UI では非表示になります。リスト間にルックアップ リレーションがあって、ルックアップ列が複数の値を許しているときは、ほとんどの場合、ターゲット リスト (そのターゲット列の値がルックアップ列の値となる) に含まれている項目の ID にアクセスする必要があります。これらの値は、ターゲット リスト内の項目を表す EntitySet<TEntity> プロパティを使用して参照できます。しかし、この場合にも、ID が LookupList<T> フィールドに格納されていると、コードがより高速に実行されます。そのため、ルックアップした値も LookupList<T> フィールドに保持するときは、このフィールドを設けてパブリックな IList<T> プロパティでラップすることをお勧めします。

これらの特殊な "ID" フィールドおよびプロパティの名前付け規則は、ルックアップした値を保持するフィールドおよびプロパティの名前付け規則と同じです。ただし、それぞれの名前を構成する 2 番目の単語として、複数形のターゲット列の名前の代わりに "Ids" が使用されます。IList<T> プロパティの [Column] 属性も同じです。

以下に、"ID" LookupList<T> フィールドとそれに対応するプロパティを追加するように拡張した Team Members 宣言と Projects 宣言を示します。

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    [Column]
    public Int32 MemberID { get; set; }

    private EntitySet<Project> assignedProjects;

    private LookupList<String> assignedProjectsTitles; 

    private LookupList<String> assignedProjectsIds; 


    [Association(List="Projects", MultiValueType=Multi)]
    public EntitySet<Project> AssignedProjects
    {
        get { return this.assignedProjects; }
        set { this.assignedProjects.Assign(value); }
    }

    [Column Name="Assigned Projects", FieldType="Lookup", IsLookupValue="true", LookupDisplayColumn="Title"]
    public IList<String> AssignedProjectsTitles 
    {
        get { return this.assignedProjectsTitles; }
        set { this.assignedProjectsTitles.Assign(value); }
    }

    [Column Name="Assigned Projects", FieldType="Lookup", IsLookupValue="true"]
    public IList<String> AssignedProjectsIds 
    {
        get { return this.assignedProjectsIds; }
        set { this.assignedProjectsIds.Assign(value); }
    }    

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

1 つの値だけを許すルックアップ リスト

単一の値をルックアップするフィールドは、単純な一対一のリレーションを表します。したがって、その値を格納するプライベート フィールドは、LookupList<T> タイプというよりも、ターゲット フィールドと同じタイプになります。同様に、このフィールドをラップするパブリック プロパティも、IList ではなく、同じタイプになります (厳密には、「[型のマッピング] LINQ to SharePoint プロバイダーから .NET」で説明しているように、フィールドおよびプロパティのタイプは、ターゲット フィールドの SharePoint Foundation タイプに対応する Microsoft .NET Framework タイプとなります)。また、値が 1 つだけなので、フィールドおよびプロパティの名前は複数形でありません。

前のセクションで説明した例のバリエーションを考えてみましょう。各チーム メンバーが 1 つのプロジェクトだけに割り当てられていて、その割り当てが Project 列に記録されているものと仮定します。この列は、Projects リストの Title 列に対するルックアップ フィールドです。この 2 つのフィールドの間のリレーションを表す EntityRef<TEntity> フィールドを使用し、さらに、TeamMember クラスで、projectTitle という名前の String フィールドと、それをラップする ProjectTitle という名前のパブリックな String クラスを宣言します。フィールドおよびプロパティの名前は単数形ですが、それ以外は、慣例に従って、ルックアップ値の名前にルックアップ フィールドの名前とターゲット フィールドの名前を連結したものを使用していることに注意してください。

[ContentType(Name = "TeamMember")]
public class TeamMember
{
    private EntityRef<Project> project;

    private String projectTitle;

    [Association(List="Projects", MultiValueType=AssociationType.Single)]
    public Project Project
    {
        get { return this.project.GetEntity(); }
        set { this.project.SetEntity(value); }
    }

    [Column Name="Project", FieldType="Lookup", IsLookupValue="true", LookupDisplayColumn="Title"]
    public String ProjectTitle 
    {
        get { return this.projectTitle.GetEntity(); }
        set { this.projectTitle.SetEntity(value); }
   }

    // Declarations of other members suppressed for readability.
}

[ContentType(Name = "Project")]
public class Project
{
    [Column]
    public String Title { get; set; }

    // Declarations of other members suppressed for readability.
}

注意

これはルックアップ フィールドから同じテーブル内の別のフィールドの値を参照する特別なケースなので、当然、テーブル間のリレーションは存在しません。そのため、EntityRef<TEntity> フィールドの宣言と、それをラップするプロパティもありません。

逆引きのルックアップ

リストのリレーションシップは、両方のコンテンツ タイプのクラスで宣言できます。こうすることで、逆引きのルックアップを行えます。ただし、このときリレーションが多対多であると、ターゲット リストの EntitySet<TEntity> プロパティは、少し異なる AssociationAttribute を持ちます。具体的には、MultivalueType プロパティに、Multi ではなく、AssociationType.Backward を設定し、Name プロパティに、ソース ルックアップ列 (逆引きのルックアップのターゲット) の内部名を設定します。

関連項目

タスク

[方法] SPMetal を使用する

参照

SPMetal

概念

オブジェクト変更追跡とオプティミスティック同時実行制御