Generics и Entity Framework: как вернуть другой тип в зависимости от значения столбца - PullRequest
3 голосов
/ 22 января 2011

У нас есть таблица Persons, в которой хранятся разные типы людей (покупатель, продавец, агент и т. Д.). Нашим ORM является Entity Framework CodeFirst (CTP5). Мы используем шаблон репозитория для хорошего TDD и насмешек. В PersonRepository я хочу вернуть определенный тип, чтобы я мог делать такие вещи:

Agent a = repository.Get<Agent>(5005);  // Where 5005 is just an example Id for the person
a.SomeAgentProperty = someValue;
Buyer b = repository.Get<Buyer>(253);   // Again, a simple PersonId.
b.SomeBuyerProperty = someOtherValue;

Идея в том, что я знаю, какого человека я получаю, когда получаю его из хранилища. И, да, я мог бы просто создать X различных методов Get, называемых GetBuyer (int PersonId), GetSeller (int PersonId) и так далее. Но это имеет запах кода.

Как будет выглядеть универсальная функция?

Вот мой интерфейс хранилища:

public interface IPersonRepository
{
    Person Get(int PersonId);   // To get a generic person
    T Get<T>(int PersonId);     // To get a specific type of person (buyer, agent, etc.)
    void Save(Person person);
    void Delete(int p);
}

И моя конкретная реализация:

    public T Get<T>(int PersonId)
    {
        //Here's my question: What goes here?
    }

Ответы [ 2 ]

3 голосов
/ 22 января 2011

Используйте метод OfType<T>(), который приведет к тому, что EF выполнит INNER JOIN с указанным T, если вы используете TPT, или фильтр на основе дискриминатора, если вы используете TPH.

public TPerson Get<TPerson>(int PersonId) where TPerson : Person
{
    return ctx.People
              .OfType<TPerson>()
              .SingleOrDefault(x => x.PersonId == PersonId);
}

Иэто будет работать так, как вы хотели:

Agent a = repository.Get<Agent>(5005);
1 голос
/ 22 января 2011

Я бы предложил использовать что-то вроде:

public T Get<T>(int PersonId) where T: new()
{
    return new T(PersonId);
}

и загрузить данные в конструктор или реализовать какой-либо метод Load для каждого типа вашей сущности, например:

interface IEntity
{
    void Load(int Id);
}

class CBuyer: IEntity
{
    public Load(int Id) { ... }
}

public T Get<T>(int PersonId) where T: IEntity, new()
{
    T ent = new T();
    ent.Load(PersonId);
    return ent;
}    
...