Помогите мне с архитектурным вопросом - PullRequest
1 голос
/ 27 июля 2011

Вот простой фрагмент:

 public interface IRepository<T>
  {
    T Get(int id);
  }

  public class Repository<T> : IRepository<T> where T : class 
  {
    private readonly IRepositoryContext _repositoryContext;
    private IObjectSet<T> _objectSet;

  public Repository(IRepositoryContext repositoryContext)
  {
    _repositoryContext = repositoryContext; 
    _objectSet = repositoryContext.GetObjectSet<T>();    
  }

   public virtual T Get(int id)
   {
       return ObjectSet.First(x=> x.Id == id) 
      // that wouldn't work because there is no guarantee that T entity has Id property
   }

Теперь, как вы можете видеть, я могу создать экземпляр Repository для любого объекта сущности и использовать определенные методы (хотя в примере у нас есть только Get (). Но я не могу использовать какие-либо ограничения в выражениях, если не создаю неабстрактный классы для каждой сущности T основаны на IRepository<T>, а затем реализуют методы так, как я хочу.

Но что, если мне нужно использовать метод, подобный Get, реализация которого остается неизменной, вероятно, для всех сущностей (у каждой сущности есть Id).

Как это сделать?

Я подумал, что мог бы создать абстрактную сущность в конструкторе модели данных EF, сопоставленную с ничем, и пометить ее как базовый тип для всех других сущностей, но он запрашивает отображение, т. Е. Таблицу. Вместо этого я попытался использовать сложный тип - это не позволило бы мне наследовать его.

Итак, покажите мне, пожалуйста, самый эффективный способ добиться этого

Ответы [ 4 ]

4 голосов
/ 27 июля 2011

Роль хранилища не в том, чтобы знать, есть ли идентификатор в вашем объекте.

Большинство хранилищ реализуют метод Single, подобный этому

public T Single( Expression<Func<T, bool>> predicate ) {
    return ObjectSet.Single<T>( predicate );
}
1 голос
/ 27 июля 2011

Лучший способ сделать то, что вы просите, - это создать собственное выражение.Примерно так:

public Expression<Func<T, bool>> GetIdEqualsExpression(int id)
{
    var idProp = typeof(T).GetProperty("ID");
    var param = Expression.Parameter(typeof(T), "t");
    return Expression.Lambda<Func<T, bool>>(
        Expression.Equal(Expression.PropertyOrField(param, "ID"),
        Expression.Constant(id)), param);
}

public virtual T Get(int id)
{
   return ObjectSet.AsQueryable().Single(GetIdEqualsExpression(id));
}

Тем не менее, Бертран хорошо заявляет, что, возможно, ответственность за обеспечение выражения должна лежать на вызывающем коде, поэтому вы не рискуете исключениями времени выполнения.

0 голосов
/ 27 июля 2011

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

//Let's call the interface IIDInterface
public interface IIDInterface
{
    int Id { get; }
}

// Now, suppose one of your entity classes is called: EntityOne
public class EntityOne : IIDInterface            
{
    // .. class constructors etc.

    // the IIDInterface interface method implementation
    public int Id
    {
        get
        {
            // getter implementation goes here
        }
    }

    // .. other members of the class
}

Тогда вы могли бы привести к интерфейсу в реализации Get и, если приведение прошло успешно, использовать свойство .Id. Функция Get становится:

public virtual T Get(int id)
{
    if(T is IIDInterface)
       return ObjectSet.First(x => ((IIDInterface)x).Id == id) 
    return default(T);
}

EDIT

Другое решение может заключаться в использовании отражения и использовании свойства Id объекта T, если оно есть. Но это может быть медленнее, и я думаю, что издержки не нужны, если вы не можете изменить объекты-сущности для реализации интерфейса IIDInterface (то есть, если вы им не являетесь)

0 голосов
/ 27 июля 2011

Вы можете использовать интерфейс:

открытый интерфейс IEntity { int Id {get; } }

тогда вместо "где T: класс" вы можете сделать "где T: IEntity" и любой объект будет иметь извлекаемый идентификатор

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...