Можно ли запретить EntityFramework 4 переписывать настроенные свойства?

Я сначала использую базу данных EF 4 + POCOs. Поскольку EF не имеет простого способа заявить, что входящие DateTimes имеют вид UTC, я переместил свойство из автоматически сгенерированного файла в частичный class в другой файл.

private DateTime _createdOn; public virtual System.DateTime CreatedOn { get { return _createdOn; } set { _createdOn = (value.Kind == DateTimeKind.Unspecified) ? _createdOn = DateTime.SpecifyKind(value, DateTimeKind.Utc) : value; } } 

Однако теперь, каждый раз, когда я обновляю модель, автоматические свойства снова создаются в генерации T4. Конечно, это приводит к следующей ошибке компиляции: «Тип« Foo »уже содержит определение для« CreatedOn ».

Есть ли способ сказать EF не генерировать это свойство и позволить мне справиться с этим самостоятельно?

Обновить

Спасибо за ответы каждого …

Я создал новое настраиваемое свойство с другим именем.

  public virtual System.DateTime CreatedOnUtc { get { return (CreatedOn.Kind==DateTimeKind.Unspecified) ? DateTime.SpecifyKind(CreatedOn, DateTimeKind.Utc) : CreatedOn; } set { CreatedOn = (value.Kind == DateTimeKind.Unspecified) ? CreatedOn = DateTime.SpecifyKind(value, DateTimeKind.Utc) : value; } } 

Я также установил все сеттеры и получатели автоматически сгенерированного свойства в Private, за исключением тех свойств, которые мне нужно было использовать в запросе Linq-to-Entities (sigh). В этих случаях я устанавливал эти геттеры на внутренние.

Я уверен, что было показано выпадающее меню в типах DateTime, чтобы указать, какой «вид» DateTime должен обрабатывать EF. Это спасло бы часы и дополнительное усложнение.

Я думаю, что все начинает запутываться, если вы пытаетесь вручную модифицировать созданные EF classы.

Есть два варианта, которые я хотел бы предложить:

  1. Не изменяйте существующее свойство, но добавьте новый в свой неполный class, CreatedOnUTC или что-то подобное.
  2. Измените шаблон T4, чтобы изменить способ создания аксессуаров для этих свойств даты (проще, если каждое свойство DateTime должно работать одинаково). Это не будет тривиально, поскольку зависит от типа, но, по крайней мере, позволит вам использовать генератор в будущем.

Другой подход – связать событие ObjectMaterialized в DbContext и установить там вид.

В моем конструкторе DbContext я делаю это:

  ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += new ObjectMaterializedEventHandler(ObjectMaterialized); 

а затем метод выглядит следующим образом:

 private void ObjectMaterialized(object sender, ObjectMaterializedEventArgs e) { Person person = e.Entity as Person; if (person != null) // the entity retrieved was a Person { if (person.BirthDate.HasValue) { person.BirthDate = DateTime.SpecifyKind(person.BirthDate.Value, DateTimeKind.Utc); } person.LastUpdatedDate = DateTime.SpecifyKind(person.LastUpdatedDate, DateTimeKind.Utc); person.EnteredDate = DateTime.SpecifyKind(person.EnteredDate, DateTimeKind.Utc); } } 

Недостатком является то, что вам нужно убедиться, что вы установите его для каждого свойства, которое вас волнует, но по крайней мере оно устанавливается на минимально возможном уровне.

Я использовал тот же подход, что и Майкл, тогда я немного погрузился в глубь и использовал рефлексию для поиска DateTime и DateTime?

Мое решение гарантировать, что все значения DateTime будут считаны как Utc DateTimes:

Сначала я написал три метода, которые находятся в моем classе методов DbContext Extensions. Потому что мне нужно использовать его для нескольких DbContexts

 public static void ReadAllDateTimeValuesAsUtc(this DbContext context) { ((IObjectContextAdapter)context).ObjectContext.ObjectMaterialized += ReadAllDateTimeValuesAsUtc; } private static void ReadAllDateTimeValuesAsUtc(object sender, ObjectMaterializedEventArgs e) { //Extract all DateTime properties of the object type var properties = e.Entity.GetType().GetProperties() .Where(property => property.PropertyType == typeof (DateTime) || property.PropertyType == typeof (DateTime?)).ToList(); //Set all DaetTimeKinds to Utc properties.ForEach(property => SpecifyUtcKind(property, e.Entity)); } private static void SpecifyUtcKind(PropertyInfo property, object value) { //Get the datetime value var datetime = property.GetValue(value, null); //set DateTimeKind to Utc if (property.PropertyType == typeof(DateTime)) { datetime = DateTime.SpecifyKind((DateTime) datetime, DateTimeKind.Utc); } else if(property.PropertyType == typeof(DateTime?)) { var nullable = (DateTime?) datetime; if(!nullable.HasValue) return; datetime = (DateTime?)DateTime.SpecifyKind(nullable.Value, DateTimeKind.Utc); } else { return; } //And set the Utc DateTime value property.SetValue(value, datetime, null); } 

И затем я перехожу к конструктору моего SiteReadModelContext, который является объектом DbContext и вызывает метод ReadAllDateTimeValuesAsUtc

 public WebsiteReadModelContext() { this.ReadAllDateTimeValuesAsUtc(); } 

Я бы использовал edmx и задал другое имя для свойства CreatedOn (например, CreatedOnInternal). Затем установите для модификатора доступа для генерации значение Internal вместо Public. Затем вы можете реализовать свое настраиваемое свойство в частичном classе и не беспокоиться об этом.

EF может быть довольно неприятным, когда дело доходит до того, что он генерирует.
В приложениях Database First, когда я сталкиваюсь с аналогичной проблемой, я обычно следую этому подходу:

  • Оставьте автогенерируемые свойства, но сделайте их private и измените их имена;
  • Добавьте общедоступные свойства «wrapping», которые имеют смысл для бизнес-кода.

Например, я бы переименовал CreatedOn в нечто другое, например, CreatedOnInternal (кредиты Jeff ) и пометить его частным в дизайнере . В частичном classе я бы добавил общедоступное CreatedOn обертки CreatedOn которое выполняет преобразование взад и вперед.

Я знаю, что это старый вопрос, но вот решение, которое не требует рефлексии или редактирования DbContext для каждого нового свойства.

Он состоит из редактирования Context.tt :

Сначала добавьте следующее, используя поверх файла tt (около строки 40):

 using System.Data.Entity.Core.Objects; 

Затем прямо под конструктором (вокруг строки 86 в моем случае) добавьте следующий код генерации:

 <# var entitiesWithDateTime = typeMapper.GetItemsToGenerate(itemCollection) .Where(e => e.Properties.Any(p => typeMapper.GetTypeName(p.TypeUsage) == "System.DateTime")); if(entitiesWithDateTime.Count() > 0) { #> private void ObjectMaterialized(object sender, ObjectMaterializedEventArgs e) { <# var count = 0; foreach (var entityType in entitiesWithDateTime) { #> <#=count != 0 ? "else " : String.Empty#>if(e.Entity is <#=entityType.Name#>) { var entity = e.Entity as <#=entityType.Name#>; <# foreach(var property in entityType.Properties.Where(p => typeMapper.GetTypeName(p.TypeUsage) == "System.DateTime")) { #> entity.<#=property.Name#> = DateTime.SpecifyKind(entity.<#=property.Name#>, DateTimeKind.Utc); <# } #> } <# count++; } #> } <# } #> 

Это будет выполняться во время компиляции во всех объектах DbContext и вызывать DateTime.SpecifyKind для каждого DateTimeProperties.

Этот код будет генерировать тот же код, что и michael.aird, но без ручного редактирования для каждого нового свойства!

  • Как сериализовать / десериализовать простые classы в XML и обратно
  • Как сопоставить разбиение таблицы в EF Code First?
  • Объекты самоконтроля и объекты POCO
  • Что такое «постоянство невежества»?
  • Первый код - сначала модель / firebase database
  • Обновление отношений при сохранении изменений объектов EF4 POCO
  • Interesting Posts

    Каковы требования в ASP.NET Identity

    Как записать образ ISO на USB-накопитель?

    Автоматическая синхронизация времени Windows чаще, чем по умолчанию.

    C ++ «виртуальное» ключевое слово для функций в производных classах. Это необходимо?

    Java – прокрутите до определенного текста внутри JTextArea

    Является ли HTML5 localStorage асинхронным?

    Лучший способ запросить страницу данных и получить общее количество в инфраструктуре сущностей 4.1?

    Последующее наблюдение: поиск точного «расстояния» между цветами

    Доступ к атрибутам на литералах работает на всех типах, но не `int`; Зачем?

    Как извлечь винт из моего корпуса ноутбука, у которого нет головы?

    Переход к предыдущему каталогу в командной строке Windows

    Когда бросать исключение?

    Как найти индекс элемента в массиве в Java?

    Является ли обычным enum Serializable тоже?

    Внешняя ошибка сборки VS2013 “ошибка MSB4019: импортированный проект не найден”

    Давайте будем гением компьютера.