2012-02-21 47 views
1

我正在使用SPMetal为我的SharePoint站点生成实体类,但我不完全确定当有多种内容类型时最佳实践是什么为单个列表。例如,我有一个任务列表,其中包含2种内容类型,我通过SPMetal的配置文件定义它们。这里是我的定义...LINQ to Sharepoint单个列表的多种内容类型

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

这似乎在生成的对象工作得很好也从WorkflowTask但对于数据的背景下产生的类型继承是WorkflowTask的名单。所以当我做一个查询时,我得到一个WorkflowTask对象而不是LegalReview或Approval对象。我如何让它返回正确类型的对象?

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

UPDATE 感谢回去我。我不知道如何重新创建基于SPListItem的类型,并希望得到任何反馈。

ContractManagementDataContext context = new ContractManagementDataContext(_url); 
WorkflowTask task = context.Tasks.FirstOrDefault(t => t.Id ==5); 
Approval a = new Approval(task.item); 

public partial class Approval{ 
    public Approval(SPListItem item){ 
     //Set all properties here for workflowtask and approval type? 
     //Wouldn't there be issues since it isn't attached to the datacontext? 
    } 

    public String SomeProperty{ 
     get{ //get from list item}; 
     set{ //set to list item}; 
} 

回答

2

Linq2SharePoint将始终为列表中的所有ContentType返回第一个公共基ContentType的对象。这不仅仅是因为必须使用某种描述的基本类型来组合代码中的不同ContentType,而且它只会映射应该在列表中的所有ContentType上肯定存在的字段。但是可以访问由L2SP返回的底层SPListItem,从而决定ContentType并向下转换该项目。

由于是从T4模板生成自定义存储库层的一部分,我们有一个局部除了由SPMetal生成的项目类,它实现ICustomMapping获得不一般的L2SP实体可用的数据。在下面的简化版本中,获取ContentType和ModifiedDate以显示方法;尽管我们使用的完整类也映射了修改者,创建日期/依据,附件,版本,路径等,但所有原则都是一样的。

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和底层SPListItem您L2SP实体可用时,它是简单地写从基本类型的值的组合返回派生的ContentType实体实例的方法的问题,并SPListItem的缺失字段的额外数据。

更新:我实际上没有示例转换器类,因为我们没有以这种方式使用上述映射扩展项。不过我能想象这样的事情会的工作:

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的部分实例的方法返回一个审批对象。

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 
     } 
    } 

在这两种情况下,你需要确定的方法调用来从WorkflowTask的ContentTypeId属性派生类型。这是我通常希望以某种形式生成的代码,因为它会非常重复,但这有点偏离主题。

+0

嗨Rob感谢您的反馈,一个很好的战略,以获得底层的SPListItem。我仍然不确定你将如何创建一个给定列表项目的实体......是否会像更新后的问题一样? – 2012-02-22 22:02:54

+0

是的,你可以做那样的事情。不需要直接从SPListItem中提取值的附加属性,因为您将在创建对象时初始化实体上的属性。你对这个实体没有被附加到上下文也是正确的。我没有包含它,因为它取决于需求,但如果您需要更新/删除,则可以将实体附加到合适的上下文中。还有其他方法可以降低,例如一个静态的EntityConverter类或每个基类型的方法。让我知道如果你需要一个例子,我会更新答案。 – robwilliams 2012-02-23 12:16:09

+0

嗨,Rob,如果你能发布你的entityconverter类的例子,如果它对你来说不是太多工作,我会很感激。再次感谢所有的帮助! – 2012-02-23 16:47:47

相关问题