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. Это тип кода, который я обычно хотел бы генерировать в той или иной форме, поскольку он будет довольно повторяющимся, но это немного не по теме.
Привет, Роб Спасибо за отзыв, что хорошая стратегия для получения базового SPListItem. Я все еще не уверен, как вы сможете создать сущность, учитывая элемент списка ... Было бы что-то вроде обновленного вопроса? –
Да, вы могли бы сделать что-то подобное. Не было бы необходимости в дополнительных свойствах, которые извлекают значения непосредственно из SPListItem, поскольку вы будете инициализировать свойства объектов при создании объекта.Вы правы в том, что сущность не привязана к контексту; Я не включил его, поскольку он зависит от требований, но вы можете прикрепить объект к подходящему контексту, если вам нужно делать обновления/удаления. Существуют и другие способы сбрасывания, например. статический класс EntityConverter или метод для каждого базового типа. Дайте мне знать, если вам нужен пример, и я обновлю ответ. – robwilliams
Привет, Роб, я был бы признателен, если бы вы могли опубликовать свой пример класса entityconverter, если это не слишком много для вас. Еще раз спасибо всем за помощь! –