LINQ2SQL: как изменить значения полей при загрузке анонимных сущностей?
!!! Пожалуйста, не перенаправляйте на в этой статье, поскольку это не решает проблему, описанную ниже.
Допустим, у нас есть такая таблица в базе:
SomeTable
- ID (int)
- DT (datetime)
мы настроили контекст данных Linq2Sql. И мы настроили сущность для SomeTable:в onloaded метод изменяет DT таким образом, что DateTimeKind DT становится Utc (изначально он не указан).
теперь вот проблема:
Если мы запрашиваем данные с помощью целого объекта, метод OnLoaded называется:
From x In ourDataContext.SomeTable Select x
но если мы запрашиваем только часть таблицы (и, следовательно, генерируем анонимный тип), OnLoaded не вызывается:
From x In ourDataContext.SomeTable Select x.DT
ясно, что OnLoaded определяется в SomeTable сущности, а не в анонимном типе.
На данный момент я считаю создание пользовательские сущности, которые заменят анонимные типы. Но, может быть, у кого-то есть лучшее решение?
5 ответов
у нас была аналогичная проблема, поскольку нам нужно было получить часть полей от сущности как анонимный объект и всегда знать, что у нас есть DateTimeKind
полей даты как DateTimeKind.UTC
без использования дополнительных функций в запросе LINQ.
мы пробовали много чего, но нашли только одно достаточно хорошее решение - генерация кода для Linq2Sql с T4.
П. С. если вы хотите узнать больше о генерации кода Linq2Sql с помощью T4, вы можете начать с http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
Linq2Sql генерирует частичные классы для таблиц, что упрощает расширение. Просто добавьте SomeTable.cs
файл в ваше решение (в том же пространстве имен, что и автоматически созданный контекст БД) и определите дополнительное свойство с любым необходимым вам поведением:
public partial class SomeTable {
public System.DateTime CustomDT {
get { return DT.AddYears(120); }
}
}
теперь вы можете запросить его, как обычно:
var e = ctx.SomeTable.Select(x => new { x.CustomDT }).First();
Console.WriteLine(e.CustomDT);
обновление:
основываясь на комментариях, я думаю, что проблема, с которой вы столкнулись, связана с неправильным разделением обязанностей. Ты попытка передать ответственность за бизнес-логику (преобразование данных) в DAL. Хотя L2S обеспечивает некоторую гибкость здесь (как показано выше), у вас есть другие варианты, если решение не удовлетворяет:
- явный слой над L2S DAL. Обычно это шаблон репозитория
это возвращает DTOs, очень похожие на те, которые автоматически генерируются L2S. В этом случае вы можете скрыть
DT
свойство заставляя потребителей использоватьCustomDT
только. - поместите логику в базу данных (представления, вычисляемые столбцы, СПС). Я не считаю этот подход для нового проекта, но это может быть жизнеспособный вариант для некоторых устаревших приложений.
вы можете указать DateTimeKind
в запросе:
from x in ourDataContext.SomeTable
select DateTime.SpecifyKind(x.DT, DateTimeKind.Utc)
если вы будете делать это часто, метод расширения может помочь сделать его менее многословен:
public static class Ext
{
public static DateTime AsUtc(this DateTime dateTime)
{
return DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
}
public static DateTime? AsUtc(this DateTime? dateTime)
{
if(dateTime == null) return null;
return AsUtc(dateTime.Value);
}
}
затем ваш запрос:
from x in ourDataContext.SomeTable select x.DT.AsUtc()
вы могли бы использовать linq-to-sql
для части запроса и использовать linq-to-objects
чтобы захватить DateTime
свойство (вы не возвращает анонимный тип).
(From x In ourDataContext.SomeTable _
Select x).AsEnumerable() _
.Select(Function(x) x.DT)
вы можете попробовать этот код? Вместо анонимного типа можно указать тот же тип таблицы, но загрузить только одно поле. Я не знаю, сработает ли это в вашем случае.
SomeTable.Select( x => new SomeTable {
DateField = x.DateField
})
в противном случае нет простого решения.