Правильное использование интерфейса с Entity Framework / Linq-to-SQL - PullRequest
0 голосов
/ 15 января 2010

Я собираюсь показать свою неопытность здесь, но эй - как любой разработчик, которого я хочу изучать.

Имеется следующий интерфейс:

public interface IRepository
{
    entityDB Database { get; set; }

    IQueryable<T> All<T>() where T:class, new();
    T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
    IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new();
}

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

Предполагая, что у меня есть сайт с портфолио фотографий, который имеет сущность Photos и сущность CameraSettings, как мне определить типы - и, следовательно, L2S - которые будут включены в мой конкретный класс? В настоящее время, когда я реализую класс, он ожидает следующую форму:

public class PhotoRepository : IRepository
{
    public override IQueryable<T> All<T>()
    {
        // code goes here...
    }

    public override T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression)
    {
        // ...and here...
    }

    public override IList<T> Find<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression)
    {
        // ... and let's not forget here.
    }
}

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

public interface IRepository<T> where T:class
{
    entityDB Database { get; set; }

    IQueryable<T> All();
    T Single<T>;
    IList<T> Find();
}

Я просто хочу, чтобы мои модульные тесты работали правильно и были уверены, что я не учусь дурным (или просто безобразным) привычкам. Оцените управляемость в правильном направлении.

Ответы [ 2 ]

2 голосов
/ 15 января 2010

В своем проекте я создал свой собственный IRepository:

public interface IRepository<T>
{
    //Retrieves list of items in table
    IQueryable<T> List();
    IQueryable<T> List(params string[] includes);
    //Creates from detached item
    void Create(T item);
    void Delete(int id);
    T Get(int id);
    T Get(int id, params string[] includes);
    void SaveChanges();
}

Вот общая реализация:

public class Repository<T> : IRepository<T> where T : EntityObject
{
    private ObjectContext _ctx;

    public Repository(ObjectContext ctx)
    {
        _ctx = ctx;
    }


    private static string EntitySetName
    {
        get
        {
            return String.Format(@"{0}Set", typeof(T).Name);
        }
    }

    private ObjectQuery<T> ObjectQueryList()
    {
        var list = _ctx.CreateQuery<T>(EntitySetName);
        return list;
    }

    #region IRepository<T> Members

    public IQueryable<T> List()
    {
        return ObjectQueryList().OrderBy("it.ID").AsQueryable();
    }

    public IQueryable<T> List(params string[] includes)
    {
        var list = ObjectQueryList();

        foreach(string include in includes)
        {
            list = list.Include(include);
        }

        return list;
    }

    public void Create(T item)
    {
        _ctx.AddObject(EntitySetName, item);
    }

    public void Delete(int id)
    {
        var item = Get(id);
        _ctx.DeleteObject(item);
    }

    public T Get(int id)
    {
        var list = ObjectQueryList();
        return list.Where("ID = @0", id).First();
    }

    public T Get(int id, params string[] includes)
    {
        var list = List(includes);
        return list.Where("ID = @0", id).First();
    }

    public void SaveChanges()
    {
        _ctx.SaveChanges();
    }

    #endregion

}

Если вы хотите простой репозиторий, вы просто используете Repository<ClassName>. Если вы хотите улучшить его, вы можете define ClassNameRepository : Repository<ClassName> и написать другие методы. Вам не нужно определять List() метод в каждом репозитории, потому что это делается в базе. Перед тем как написать свой репозиторий, я сделал предположение:

  • Каждое поле первичного ключа в моей базе данных называется ID.
  • Каждое EntitySetName создается из имени класса и Set. Для User класса это будет UserSet.

Это решение использует Dynamic LINQ:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Работает довольно хорошо.

2 голосов
/ 15 января 2010

Если я вас правильно понял, вы хотите создать отдельные репозитории для каждой вашей сущности (или только для нескольких из них). В этом случае подходящим решением будет использовать вторую версию интерфейса, которую вы разместили. Как это:

public interface IRepository<T> where T : class, new()
{
    entityDB Database { get; set; }

    IQueryable<T> All();
    T Single(Expression<Func<T, bool>> expression);
    IList<T> Find(Expression<Func<T, bool>> expression);
} 

И реализация PhotoRepository будет выглядеть так:

public class PhotoRepository : IRepository<Photo>
{
    public IQueryable<Photo> All()
    {
        // code goes here...
    }

    public Photo Single(Expression<Func<Photo, bool>> expression)
    {
        // ...and here...   
    }

    public IList<Photo> Find(Expression<Func<Photo, bool>> expression)
    {
        // ... and let's not forget here.   
    }
}

Также, если ваши репозитории будут работать с сущностями Entity Framework, вы можете более точно определить интерфейс IRepository:

public interface IRepository<T> where T : EntityObject, new()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...