шаблон проектирования для уровня доступа к данным

<p>вы можете почувствовать, что это домашнее задание, за это я извиняюсь. я искал, но не мог найти правильный ответ.</p><p>итак, мой вопрос:</p><p>у меня есть несколько классов, и у каждого класса есть метод для сохранения. поэтому я создал отдельный класс для обработки базы данных.</p><pre><code>namespace hospitalmgt.data { public static class dbconnection { public static string constr = "data source=abd;initial catalog=hospitalmgt;user id=sa;password=123"; public static sqlconnection con; // public static sqlcommand com; public static sqlconnection openconnection() { con= new sqlconnection(constr); con.open(); return con; } } } </code></pre><p>однако я не думаю, что это целесообразно для реализации всех классов с классом dbconnection.</p><p><strong> мой вопрос : </strong></p><ol> <li>какой шаблон проектирования подходит для преодоления этой проблемы?</li> <li>это хорошая практика для создания dbconnection как класс? (или это должен быть интерфейс)</li> </ol><p>я нашел несколько статей о слоях da с использованием метода factory, но, насколько мне известно, этот шаблон не подходит для моей ситуации. </p>

<p>обычно, если я не могу использовать какой-либо существующий фреймворк, я использую шаблоны repository и active. </p><p>для простоты вы можете использовать только шаблон repository. я обычно определяю это так:</p><pre><code>// define a generic repository interface public interface irepository<key, e> where e:ientity<key>>{ void add(e entity); void addrange(ienumerable<e> entities); ientity<key> get(key key); ienumerable<e> getrange(ienumerable<key> keys); ienumerable<e> getall(); // ..., update, delete methods } // create an abstract class that will encapsulate the generic code public abstract class repository<k, e> where e:ientity<k>>:irepository<k, e>{ protected repository(/*parameter you may need to implement the generic methods, like a connectionfactory, table name, entity type for casts, etc */){} public override void insert(ientity<key> entity){ // do the insert, treat exceptions accordingly and encapsulate them in your own and more concise exceptions, etc } // ... } // create the entities classes, one for each table, that will represent a row of that table public class car: ientity<string>{/* properties */} // create a specific repository for each table // if the table have a composed key, just create a class representing it public carrepository: repository<string, car>{ public carrepository(){/* pass the base parameters */} // offer here your specific operations to this table entity public ienumerable<car> getbyowner(personkey ownerkey){ // do stuff } } </code></pre><p>теперь у вас есть достаточно инструментов для работы с базой данных, но при желании вы можете использовать шаблон active . простой пример:</p><pre><code>public class person:ientity<personkey>{ public personkey key{get;} public ienumerable<car> ownedcars{ get{ carrepository rep = dbsingletons.cars; return rep.getbyowner(this.key); } set{ // do stuff } } } </code></pre><p>очевидно, что при выполнении ваших собственных реализаций вы должны принимать во внимание безопасность потоков, обеспечивающую хорошее использование транзакций, особенно в разных репозиториях сущностей.</p><pre><code>// simple example itransaction t = transactionfactory.getnewtransaction(); t.begin(); try{ // create person entity personrepository.add(person, t); // create cars assigned to person carrepository.addrange(cars, t); t.commit(); }catch(exception){ t.rollback(); } </code></pre><p>просто убедитесь, что вы действительно хотите создать свой собственный dal, так как он может оказаться чрезвычайно сложным, особенно пытаясь разработать наиболее универсальное решение.</p>

<p>я предлагаю использовать orm, entity framework или nhibernate. тогда вам не нужно беспокоиться о контексте бд или создавать операторы sql.</p>

<p>прежде всего, я хотел бы порекомендовать вам статью <a href="http://msdn.microsoft.com/en-us/magazine/dd569757.aspx">«шаблоны проектирования для персистентности данных» джереми миллера</a> .</p><p>существует несколько шаблонов уровня доступа к данным:</p><ol> <li> <a href="http://martinfowler.com/eaacatalog/activerecord.html">шаблон активной записи</a> ( <a href="http://en.wikipedia.org/wiki/active\_record\_pattern">wiki</a> , <a href="http://msdn.microsoft.com/en-us/magazine/dd419658.aspx#id0070001">подробная информация</a> ).</li> <li> <a href="http://martinfowler.com/eaacatalog/repository.html">шаблон репозитория</a> ( <a href="http://msdn.microsoft.com/en-us/library/ff649690.aspx">подробная информация</a> ).</li> </ol>

<p>я предлагаю вам использовать repositorybase для всех этих общих операций. если вы решите использовать orm для доступа к данным, хорошо подумать о реализации репозиториев на основе репозитория универсального типа. </p><p>вот хорошая статья об этом:</p><p> <a href="http://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/">http://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/</a> </p>

<p>это слишком старое, но только что пришло время ответить на этот вопрос и не смог удержаться, чтобы оставить свои мысли.</p><p>я нашел <a href="https://stackoverflow.com/a/45460483/5779732">репозиторий</a> с <a href="https://stackoverflow.com/a/45029588/5779732">unitofwork</a> с некоторым спуском orm - хороший подход. это минимизирует большинство проблем.</p><p>uow, упомянутый в ссылке выше, может быть введен в репозиторий. это увеличивает гибкость использования. кроме того, весь код связи с бд централизован в одном месте. пример не завершен, но является точкой запуска.</p><p>шаблон репозитория, упомянутый в ссылке выше, на самом деле является базовым базовым классом. вы можете создать новый класс для каждого вашего конкретного репозитория, производного от него.</p><p>общий репозиторий считается анти-паттерном; есть много статей в интернете, которые объясняют это.</p><p><strong>почему общий репозиторий является антишаблоном?</strong></p><ol> <li>репозиторий является частью моделируемого домена, и этот домен не является универсальным . <ul> <li>не каждая сущность может быть удалена.</li> <li>не каждая сущность может быть добавлена</li> <li>не у каждого объекта есть хранилище.</li> <li>запросы сильно различаются; api хранилища становится таким же уникальным, как и сам объект.</li> <li>для <code>getbyid()</code> типы идентификаторов могут быть разными.</li> <li>обновление определенных полей (dml) невозможно.</li> </ul></li> <li>за общий механизм запросов отвечает orm . <ul> <li>большинство orm предоставляют реализацию, которая очень похожа на generic repository.</li> <li>репозитории должны реализовывать специальные запросы для сущностей, используя общий механизм запросов, предоставляемый orm.</li> </ul></li> <li>работа с составными ключами невозможна.</li> <li>в любом случае, это приводит к утечке логики dal в службах.<ul> <li>критерии предиката, если вы принимаете их в качестве параметра, должны быть предоставлены из сервисного уровня. если это специфичный для orm класс, он пропускает orm в сервисы.</li> </ul></li> </ol><p>я предлагаю вам прочитать эти ( <a href="http://blog.sapiensworks.com/post/2012/04/15/the-repository-pattern-vs-orm.aspx">1</a> , <a href="http://blog.sapiensworks.com/post/2012/03/05/the-generic-repository-is-an-anti-pattern.aspx">2</a> , <a href="https://ayende.com/blog/3955/repository-is-the-new-singleton">3</a> , <a href="http://www.ben-morris.com/why-the-generic-repository-is-just-a-lazy-anti-pattern/">4</a> , <a href="https://rob.conery.io/2014/03/03/repositories-and-unitofwork-are-not-a-good-idea/">5</a> ) статьи, объясняющие, почему универсальный репозиторий является anit-pattern.</p><p><strong>решение:</strong></p><ol> <li>напишите абстрактный универсальный репозиторий, который обернут конкретным репозиторием. таким образом, вы можете управлять общедоступным интерфейсом, но при этом иметь возможность повторного использования кода, получаемого из общего репозитория.</li> <li>используйте универсальный репозиторий, но используйте композицию вместо наследования и не выставляйте ее домену в качестве контракта.</li> </ol><p>в любом случае, не подвергайте generic repository вызывающему коду. также не выставляйте <code>iqueryable</code> из конкретных репозиториев.</p>