2012-11-23 6 views
4

У меня есть код повторного ввода кода в моем резервном хранилище EntityFramework, который я хотел бы каким-то образом обобщить и вызвать как метод, чтобы повторно использовать код, а не повторять его.Рефакторинг кода в общий метод

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

 // Archive deleted MyItems sections 
     _t.MyItems.Where(x => x.ValidTo == null && !team.MyItems.Contains(x)).ToList().ForEach(x => x.ValidTo = DateTime.Now); 

     // Add or update MyItems sections 
     foreach (var MyItemsSection in team.MyItems) 
     { 
      if (MyItemsSection.Id == default(int)) 
      { 
       MyItemsSection.ValidFrom = DateTime.Now; 
       _t.MyItems.Add(MyItemsSection); 
      } 
      else 
      { 
       var _MyItemsSection = _t.MyItems.FirstOrDefault(x => x.Id == MyItemsSection.Id); 
       context.Entry(_MyItemsSection).CurrentValues.SetValues(MyItemsSection); 
      } 
     } 

_t является EntityFramework связного графа объекта, в то время как team является идентичным типом объекта графа, который был отключен и, возможно, обновлением извне. Целью здесь является синхронизация двух графиков объектов, чтобы изменения сохранялись.

Мне нужно передать в _t.MyItems и team.MyItems, где MyItems должны быть genericised так же метод работает для MyOtherItems и MySocks, MyUnderPants и т.д.

Является ли это вообще возможно?

+1

Если мы предположим, что 'MyItems' - это коллекция' T', то все остальные 'T' имеют свойства' Id' и 'ValidTo'? Это похоже на то, чтобы сделать это более общим и работать с разными коллекциями. – Jamiec

+0

Я думаю, вы должны опубликовать это на codereview: http://codereview.stackexchange.com/ – maxbeaudoin

+0

Да, у всех есть Id и ValidTo, но контекст. Entry(). CurrentValues.SetValues ​​() по-прежнему необходимо работать, поэтому интерфейс, основанный только на этих двух свойствах, не будет работать. Хотя я не знаю, как это сделать, я уверен, что мне нужно также передать типы. – Moo

ответ

1

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

Итак, вот что я придумал:

public void UpdateEntities<TEntity>(ICollection<TEntity> pocoCollection, ICollection<TEntity> dbCollection) 
     where TEntity : class, IEntity 
    { 
     // Archive deleted entities 
     dbCollection.Where(x => x.ValidTo == null && !pocoCollection.Contains(x)).ToList().ForEach(x => x.ValidTo = DateTime.Now); 

     // Add or update entities 
     foreach (var entity in pocoCollection) 
     { 
      if (entity.Id == default(int)) 
      { 
       entity.ValidFrom = DateTime.Now; 
       dbCollection.Add(entity); 
      } 
      else 
      { 
       var _entity = dbCollection.FirstOrDefault(x => x.Id == entity.Id); 
       context.Entry(_entity).CurrentValues.SetValues(entity); 
      } 
     } 
    } 

Часть, которую я искал был where TEntity : class, IEntity

В этом решении, я должен убедиться, что мои объекты реализуют интерфейс IEntity, который просто:

public interface IEntity 
{ 
    int Id { get; set;} 
    DateTime ValidFrom { get; set; } 
    DateTime? ValidTo { get; set; } 
} 

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

Надеюсь, это поможет кому-то еще.

1

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

Ограничения:

// base type 
interface IFoo { 
    int ID { get; set; } 
} 

    // generic method 
    public List<T> Update<T>(List<T> graph1, List<T> graph2) where T : IFoo { 
    var update = graph1.Intersect(graph2, (g1, g2) => { g1.ID == g2.ID }).ToList(); 
    return update; 
    } 

Предикаты:

public void Update<T, U>(T _t, T team, Func<T, IList<U>> selector) 
{ 
    var _tItems = selector(_t); 
    var teamItems = selector(team); 

    // Archive deleted MyItems sections 
    _tItems.Where(x => x.ValidTo == null && !teamItems.Contains(x)).ToList().ForEach(x => x.ValidTo = DateTime.Now); 

    // Add or update MyItems sections 
    foreach (var MyItemsSection in teamItems) 
    { 
     if (MyItemsSection.Id == default(int)) 
     { 
      MyItemsSection.ValidFrom = DateTime.Now; 
      _tItems.Add(MyItemsSection); 
     } 
     else 
     { 
      var _MyItemsSection = _tItems.FirstOrDefault(x => x.Id == MyItemsSection.Id); 
      context.Entry(_MyItemsSection).CurrentValues.SetValues(MyItemsSection); 
     } 
    } 
} 

    //Usage: 
    Update(_t, team, (t => t.MyItems)); 

Но опять же, что удерживает вас от написания метод, который принимает списки в качестве параметров?

Как и в public void Update<T>(IList<T> _tItems, IList<T> teamItems)

+0

Ограничение базового типа не будет работать, потому что они будут отличаться - структура, которую я хочу обобщить, скорее является продуктом работы EF, чем моей собственной деятельностью, поэтому EF все еще должна иметь возможность делать свою работу. Я не знаю, заметили ли вы, но в моем примере кода есть три вещи: архивирование удаленных элементов, добавление новых элементов и обновление существующих элементов. EF делает просто слияние объектных графов проблематичным по разным причинам. – Moo

+1

@Moo - вы можете ограничить их базовым интерфейсом, который можно добавить к объектам либо путем изменения шаблона T4, либо в новом файле с другой частью объекта класса «partial». Это не будет мешать EF вообще, и если EF уже генерирует свойства, которые требуется интерфейсу, вам не нужно ничего делать. – Bobson

+0

Я понимаю это, но не будет context.Entry(). CurrentValues.SetValues ​​() будет получать тип, отличный от типа, который он ожидает (т. Е. Сущность)? Поскольку вы можете просто передать объект как в Entry(), так и в SetValues ​​(), я не совсем уверен, что передача в ограниченном типе не приведет к тому, что EF пропустит тот факт, что я передаю два типа сущностей, он знает. Имеет ли это смысл? – Moo

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