2012-02-21 2 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 или утверждения. Как заставить объект вернуть правильный тип?

[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 для всех ContentTypes в списке. Это связано не только с тем, что базовый тип некоторого описания должен использоваться для объединения разных ContentTypes в коде, но также он будет отображать только поля, которые обязательно должны существовать во всех ContentTypes в списке. Тем не менее, возможно получить доступ к базовому SPListItem, возвращенному L2SP, и, следовательно, от этого определить ContentType и опустить элемент.

Как часть пользовательского слоя репозитория, созданного из шаблонов T4, мы имеем частичное дополнение к классу Item, сгенерированному 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; 
    } 
} 
} 

После того, как у вас есть ТипСодержимый и основной SPListItem доступен на вашем L2SP сущности это просто вопрос написания метода, который возвращает экземпляр производного ContentType объекта из комбинации значений базового типа и дополнительные данные для отсутствующих полей из SPListItem.

UPDATE: На самом деле у меня на самом деле нет примерного класса преобразователя, так как мы не используем вышеописанное расширение расширения для 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 вернуть объект утверждения.

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

В любом случае вам нужно будет определить метод для вызова, чтобы получить производный тип из свойства ContentTypeId в WorkflowTask. Это тип кода, который я обычно хотел бы генерировать в той или иной форме, поскольку он будет довольно повторяющимся, но это немного не по теме.

+0

Привет, Роб Спасибо за отзыв, что хорошая стратегия для получения базового SPListItem. Я все еще не уверен, как вы сможете создать сущность, учитывая элемент списка ... Было бы что-то вроде обновленного вопроса? –

+0

Да, вы могли бы сделать что-то подобное. Не было бы необходимости в дополнительных свойствах, которые извлекают значения непосредственно из SPListItem, поскольку вы будете инициализировать свойства объектов при создании объекта.Вы правы в том, что сущность не привязана к контексту; Я не включил его, поскольку он зависит от требований, но вы можете прикрепить объект к подходящему контексту, если вам нужно делать обновления/удаления. Существуют и другие способы сбрасывания, например. статический класс EntityConverter или метод для каждого базового типа. Дайте мне знать, если вам нужен пример, и я обновлю ответ. – robwilliams

+0

Привет, Роб, я был бы признателен, если бы вы могли опубликовать свой пример класса entityconverter, если это не слишком много для вас. Еще раз спасибо всем за помощь! –

Смежные вопросы