2014-10-27 3 views
1

Моего сценария:Базовый класс Enum реализованы по-разному в производных классов

public class EntityBase 
{ 
    public int ID { get; set; } 
    [Required()] 
    public string Name { get; set; } 
    //And this is what is getting me 
    //I want a "Type" enum 
} 

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

public class AnimalEntity : EntityBase 
{ 
    //Type would have an 'animal type' value: Land, Sea or Air 
    //Implementation code would do something like: 
    // myAnimal.Type = AnimalType.Land 
} 

public class PersonEntity : EntityBase 
{ 
    //Type would have a 'person type' value: Doctor, Lawyer or Engineer 
    //Implementation code would do something like: 
    // myPerson.Type = PersonType.Lawyer 
} 

public class MonsterEntity : EntityBase 
{ 
    //Type would have a 'monster type' value: Goblinoid, Undead 
} 

Итак, большой вопрос, что я пытаюсь сделать, правильно? Я пытаюсь создать базовый класс репозитория, который будет возвращать сущности, сгруппированные по типу. Все мои сущности будут иметь какой-то «тип», и я хочу создать общую «группу по типу».

public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : EntityBase 
{ 
    //Our common GetAsync, GetByIdAsync, and all our other CRUD 

    //And then something like this: 
    public IEnumerable<GroupedData<string, T>> GetGroupedByType(string searchTerm) 
    { 
     var entities = 
      from s in DbSet 
      where (searchTerm == null || s.Name.ToLower().Contains(searchTerm)) 
      group s by s.Type into g 
      select new GroupedData<string, T> { Key = g.Key.ToString(), Data = g }; 

     return (entities); 
    } 
} 

Когда T является AnimalEntity, я получаю группы Land, Sea и Air с соответствующими объектами. Для PersonEntity я хотел бы получить группы Doctor, Lawyer, Engineer.

Если мой подход/дизайн недействителен или не идеален, сообщите мне.

+1

Что не так с указанием перечисления в родовом? 'EntityBase ' и т. Д. Я не уверен, что я решил сделать это сам, чтобы быть честным, но это все равно возможно. Тем не менее, я понятия не имею, как вы интегрируете это в группировку. Я лично не буду создавать стиль, основанный на попытке комбинировать общий код. Я бы проектировал материал, а затем определял, где находится общая логика. Например, вместо изменения enum, почему бы не каждый производный репозиторий реализовать функцию группировки? –

+0

@AdamHouldsworth Если я ошибаюсь, похоже, что цель состоит в том, чтобы ввести типизированное перечисление производного класса в качестве ключа. Джейсон, ты можешь это подтвердить? – samy

+0

@AdamHouldsworth - Я начинаю приближаться к вашей линии мышления. Попытка абстрагировать группу по типу может оказаться недостаточной для всех остальных обручей. Благодарю. – Jason

ответ

1

Enum (простите пожалуйста меня) является своим родом второго класса граждан так первое, что вы можете думать о том, будет не работает:

class EntityBase<T> where T : enum { 
    public T Type { get; set; } 
} 

К сожалению, это не компилируется, вы можете потом думать заменить enum с базовым классом:

class EntityBase<T> where T : EntityTypeBase { 
    public T Type { get; set; } 
} 

Реализация в EntityTypeBase все, что нужно, чтобы быть удобные с ними (== и != операторы, IConvertible интерфейс и другие шаблоны). Это много кода, и вам также нужно будет управлять этим в EF (иначе вы не сможете использовать такое свойство в своих запросах, если вы не загружаете все в память как объекты). Вы также можете использовать force the use of enums (с проверкой времени выполнения), но это приведет к поломке генерации кода SQL в EF.

Что я предлагаю в этом случае должен использовать тип EF, который знает и понимает. Вы можете использовать строку (если вы хотите так) или целое число (как в данном примере):

class EntityBase 
    public virtual int Type { get; set; } 
} 

В производном классе:

class AnimalEntity : EntityBase { 
    public override int Type { 
     get { return base.Type; } 
     set { 
      if (!Enum.IsDefined(typeof(AnimalType), value)) 
       throw new ArgumentException(); 

      base.Type = (int)value; 
     } 
    } 
} 

Таким образом, вы все еще можете использовать PersonType.Layer и AnimalType.Land сохраняя также немного безопасности типа. Разумеется, вам нужно сохранить синхронизацию в очереди, чтобы не иметь дублированных значений (иначе group by не будет работать).

Как последний пожалуйста, также рассмотрите использование ... другой объект. Если у вас есть еще один стол EntityType:

 
ID Name   ApplicableTo 
0  Laywer  Person 
1  Programmer Person 
2  Land   Animal 
... 

То, что вы должны сделать в инкубаторе должен проверить, если тип применит или нет, и вы можете иметь несколько удобных классов, которые будут группироваться их по типу:

public static class PersonType { 
    public static EntityType Lawyer { get { ... } } 
    public static EntityType Programmer { get { ... } } 
} 

ИМО это масштаб лучше (проще добавлять новые элементы и вы можете делегировать, в будущем, некоторое поведение EntityType элементов) и безопаснее чем жестко закодированные константы (так как целостность предоставлено сам DB двигателем) , Конечно, цена для оплаты - дополнительные накладные расходы для поиска в таблице EntityType (если вы не используете какой-либо механизм кеширования).

+0

'где T: enum' действительно не работает. Я надеялся, что это тоже произошло :( –

+0

@PatrickHofman да, это не всегда полезно, но иногда я бы хотел его увидеть! –

+0

Да, +1 в любом случае. Это не ваша вина;) –

1

Два варианта я могу думать:

Во-первых, предпочтительно использовать generic type parameter (T в данном примере):

public class EntityBase<T> 
{ 
    public T Type {get;set;} 
} 

питания, что тип в объявлении типа:

public class AnimalEntity : EntityBase<AnimalEnum> 
{ } 

Во-вторых, если вам нужна больше свободы, я обычно использую список string участников:

public class EntityBase 
{ 
    public string Type {get;set;} 
} 

public static class AnimalTypes 
{ 
    public const string Dog = "dog"; 
    public const string Cat = "cat"; 
} 
+0

Спасибо за отзыв. Я думал об этом, но надеялся на что-то еще более чистое. – Jason

+0

В EF последний вариант должен работать, не так ли? –

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