2012-02-21 9 views
1

私はSharepointサイトのエンティティクラスを生成するためにSPMetalを使用していますが、複数のコンテンツタイプがある場合のベストプラクティス単一のリストのために。たとえば、2つのコンテンツタイプを含むタスクリストがあり、SPMetalの設定ファイルを使ってそれらを定義しています。ここに私の定義がある...LINQ-to-Sharepoint単一のリストの複数のコンテンツタイプ

<List Member="Tasks" Name="Tasks"> 
    <ContentType Class="LegalReview" Name="LegalReviewContent"/>  
    <ContentType Class="Approval" Name="ApprovalContent"/>  
</List> 

これは、生成されたオブジェクトがWorkflowTaskから継承しないということでかなりよく動作するようですが、データコンテキストの生成タイプはWorkflowTaskの一覧です。ですから、私がクエリを実行すると、LegalReviewまたはApprovalオブジェクトの代わりにWorkflowTaskオブジェクトが返されます。正しい型のオブジェクトを返すにはどうすればよいですか?

[Microsoft.SharePoint.Linq.ListAttribute(Name="Tasks")] 
public Microsoft.SharePoint.Linq.EntityList<WorkflowTask> Tasks { 
    get { 
     return this.GetList<WorkflowTask>("Tasks"); 
    } 
} 

更新日 私に戻ってくれてありがとう。私はSPListItemに基づいてどのように型を作り直したのか分かりませんし、フィードバックをいただければ幸いです。

答えて

2

Linq2SharePointは、リスト内のすべてのContentTypesの最初の共通ベースContentTypeのオブジェクトを常に返します。これは、コード内の異なるContentTypesを結合するためにいくつかの説明の基本型を使用する必要があるだけでなく、リスト内のすべてのContentTypesに確実に存在するはずのフィールドだけをマップするためです。しかし、L2SPによって返された基になるSPListItemにアクセスすることができ、したがってContentTypeを決定し、アイテムをダウンキャストすることが可能です。

T4テンプレートから生成されたカスタムリポジトリレイヤの一部として、通常はL2SPエンティティで利用できないデータを取得するためにICustomMappingを実装するSPMetalによって生成されたItemクラスに部分的に追加されています。単純化されたバージョンは以下の通りで、方法論を示すためにContentTypeとModifiedDateを取得します。私たちが使用するフルクラスは、Modified By、Created Date/By、Attachments、Version、Pathなどのマップもありますが、原則はすべて同じです。

public partial class Item : ICustomMapping 
{ 
private SPListItem _SPListItem; 
public SPListItem SPListItem 
{ 
    get { return _SPListItem; } 
    set { _SPListItem = value; } 
} 
public string ContentTypeId { get; internal set; } 
public DateTime Modified { get; internal set; } 

public virtual void MapFrom(object listItem) 
{ 
    SPListItem item = (SPListItem)listItem; 
    this.SPListItem = item; 
    this.ContentTypeId = item.ContentTypeId.ToString(); 
     this.Modified = (DateTime)item["Modified"]; 
} 

public virtual void MapTo(object listItem) 
{ 
    SPListItem item = (SPListItem)listItem; 
     item["Modified"] = this.Modified == DateTime.MinValue ? this.Modified = DateTime.Now : this.Modified; 
} 

public virtual void Resolve(RefreshMode mode, object originalListItem, object databaseObject) 
{ 
    SPListItem originalItem = (SPListItem)originalListItem; 
    SPListItem databaseItem = (SPListItem)databaseObject; 

     DateTime originalModifiedValue = (DateTime)originalItem["Modified"]; 
     DateTime dbModifiedValue = (DateTime)databaseItem["Modified"]; 

    string originalContentTypeIdValue = originalItem.ContentTypeId.ToString(); 
    string dbContentTypeIdValue = databaseItem.ContentTypeId.ToString(); 

    switch(mode) 
    { 
     case RefreshMode.OverwriteCurrentValues: 
       this.Modified = dbModifiedValue; 
      this.ContentTypeId = dbContentTypeIdValue; 
      break; 

     case RefreshMode.KeepCurrentValues: 
       databaseItem["Modified"] = this.Modified; 
      break; 

     case RefreshMode.KeepChanges: 
       if (this.Modified != originalModifiedValue) 
       { 
        databaseItem["Modified"] = this.Modified; 
       } 
       else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue) 
       { 
        this.Modified = dbModifiedValue; 
       } 
      if (this.ContentTypeId != originalContentTypeIdValue) 
      { 
       throw new InvalidOperationException("You cannot change the ContentTypeId directly"); 
      } 
      else if (this.ContentTypeId == originalContentTypeIdValue && this.ContentTypeId != dbContentTypeIdValue) 
      { 
       this.ContentTypeId = dbContentTypeIdValue; 
      }     
      break; 
    } 
} 
} 

あなたがたContentTypeとあなたのL2SPエンティティで利用可能な基礎となるSPListItemを持っていたら、それは単に基本型の値の組み合わせから派生したContentTypeのエンティティのインスタンスを返すメソッドを記述の問題であり、 SPListItemから欠落しているフィールドの余分なデータ

更新:私はこのような方法でItemに上記のマッピング拡張を使用しないので、実際にはコンバータクラスの例はありません。しかし、私はこのような何かが働くだろうと想像できます。

public static class EntityConverter 
{ 
    public static Approval ToApproval(WorkflowTask wft) 
    { 
     Approval a = new Approval(); 
     a.SomePropertyOnWorkflowTask = wft.SomePropertyOnWorkflowTask; 
     a.SomePropertyOnApproval = wft.SPListItem["field-name"]; 
     return a; 
    } 
} 

それとも、承認オブジェクトを返すためにWorkflowTaskの部分的なインスタンスでメソッドを入れることができます。あなたがWorkflowTaskのContentTypeIdプロパティから派生した型を取得するために呼び出すメソッドを決定する必要があるのいずれかの状況では

public partial class WorkflowTask 
    { 
     public Approval ToApproval() 
     { 
      Approval a = new Approval(); 
      a.SomePropertyOnWorkflowTask = this.SomePropertyOnWorkflowTask; 
      a.SomePropertyOnApproval = this.SPListItem["field-name"]; 
return a; 
     } 

     public LegalReview ToLegalReview() 
     { 
      // Create and return LegalReview as for Approval 
     } 
    } 

。これは、通常はあるフォームまたは別のフォームで生成したいコードのようなものです。かなり繰り返しますが、それは少し話題になります。

+0

こんにちは、Robおかげで、基礎となるSPListItemを取得するという良い戦略がありました。リスト項目を指定してエンティティを作成するにはどうすればいいのかまだ分かりません...更新された質問のようなものでしょうか? –

+0

はい、そういうことをすることができます。オブジェクトを作成するときにエンティティのプロパティを初期化するときに、SPListItemから直接値を取得する追加のプロパティは必要ありません。あなたは、エンティティがコンテキストにも添付されていないことについて正しいです。要件に依存するので、私はそれを含めませんでしたが、更新/削除を行う必要がある場合は、エンティティを適切なコンテキストにアタッチすることができます。ダウンキャストには他にも方法があります。静的なEntityConverterクラスまたは各基本型のメソッド例が必要な場合は教えてください。答えを更新します。 – robwilliams

+0

こんにちはロブ、私はあなたがあなたのためのあまり仕事ではない場合は、エンティティコンバータクラスの例を投稿することができれば感謝したいと思います。すべての助けをありがとう! –

関連する問題