LINQ-To-Sharepoint Несколько типов контента для одного списка - PullRequest
1 голос
/ 22 февраля 2012

Я использую SPMetal для создания классов сущностей для своего сайта sharepoint, и я не совсем уверен, что лучше всего использовать, когда для одного списка существует несколько типов контента.Например, у меня есть список задач, который содержит 2 типа контента, и я определяю их через файл конфигурации для SPMetal.Вот мое определение ...

<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");
    }
}

ОБНОВЛЕНИЕ Спасибо, что ответили мне.Я не уверен, как я воссоздаю тип, основанный на 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};
}

1 Ответ

2 голосов
/ 22 февраля 2012

Linq2SharePoint всегда будет возвращать объект первого общего базового ContentType для всех 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;
    } 
}
}

Как только у вас есть ContentType и базовый SPListItem, доступный для вашей сущности L2SP, это просто вопрос написания метода, который возвращает экземпляр производной сущности 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 для возврата объекта Approval.

    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.Это тот код, который я обычно хотел бы генерировать в той или иной форме, так как он будет довольно повторяющимся, но это немного не по теме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...