if($stmt->fetchColumn() >= 0)
{
$stmt->execute(); //Reset cursor
while($rs = $stmt->fetchObject())
{
echo "Data: ".$rs->data;
}
}
else
{
echo '0';
}
Я думаю, что все они хорошие варианты (кроме, может быть, 4, если вы не хотите привязывать себя к спящему режиму), и у вас, похоже, есть все плюсы и минусы, хорошо проанализированные, чтобы принять решение о своем владеть на основе ваших текущих усилий. Не ругайте себя слишком за это.
В настоящее время я работаю над смесью от 2 до 3, я полагаю:
public interface IRepository<T>
{
...
IList<T> FindAll();
IList<T> FindBySpec(ISpecification<T> specification);
T GetById(int id);
}
public interface ISpecificRepository : IRepository<Specific>
{
...
IList<Specific> FindBySku(string sku);
IList<Specific> FindByName(string name);
IList<Specific> FindByPrice(decimal price);
}
И есть также базовый класс репозитория (T).
There's also a good argument for a "none of the above" approach.
The problem with generic repositories is that you're making the assumption that all objects in your system will support all four CRUD operations: Create, Read, Update, Delete. But in complex systems, you'll likely have objects that support only a few of the operations. For instance, you might have objects that are read-only, or objects that are created but never updated.
You could break the IRepository interface into small interfaces, for Read, Delete, etc. but that gets messy pretty quickly.
Gregory Young makes a good argument (from a DDD / software layering perspective) that each repository ought to support only the operations that are specific to the domain object or aggregate you're working with. Here's his article on generic repositories.
And for an alternate view, see this Ayende blog post.
Одна из вещей, которые мы делаем, заключается в том, что у всех наших репозиториев разные потребности, поэтому мы создаем набор интерфейсов:
public interface IReadOnlyRepository<T,V>
{
V Find(T);
}
В этом примере репозиторий только для чтения просто получает из база данных. Причина для T, V заключается в том, что V представляет то, что возвращается репозиторием, а T представляет то, что передается, поэтому вы можете сделать что-то вроде этого:
public class CustomerRepository:IReadOnlyRepository<int, Customer>, IReadOnlyRepository<string, Customer>
{
public Customer Find(int customerId)
{
}
public Customer Find(string customerName)
{
}
}
Я также могу создать отдельные интерфейсы для Add, Update и Удалять. Таким образом, если моему репозиторию не требуется поведение, тогда он просто не реализует интерфейс.
Я большой поклонник 1, потому что я могу создавать фильтры и методы расширения разбиения по страницам, которые я могу применить к возвращаемым значениям IQueryable <> для метода Find. Я сохраняю методы расширения на уровне данных, а затем создаю на лету на бизнес-уровне. (Не совсем чисто, надо признать.)
Конечно, когда система стабилизируется, у меня есть возможность создать определенные методы поиска с использованием тех же методов расширения и оптимизировать с помощью Func <>.
Wither the Repository
Соответствующая статья Джимми Богарда из LosTechies
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/10/wither-the-repository.aspx
Кроме того, еще одна небольшая статья с некоторыми комментарии, предполагающие, что версия №2 на самом деле является шаблоном DOA, а не репозиторием.
http://fabiomaulo.blogspot.com/2009/06/linq-and-repository.html
При использовании NH с Linq ваш репозиторий может быть:
session.Linq<Entity>()
Спецификации - это вещи, которые касаются:
IQueryable<Entity>
Вы можете скрыть все это, если хотите, но это много повседневная работа по абстракции абстракции.
Простота - это хорошо. Да, NH создает базы данных, но предоставляет гораздо больше шаблонов. Иметь зависимость от NH, отличную от DAL, далеко не грех.