Pergunta

I inicialmente concebido meu sistema seguindo o exemplo s # arquitetura descrito neste artigo codeproject (Infelizmente, eu não estou usando NHibernate). A idéia básica é que para cada objeto de domínio que seria necessário para se comunicar com a camada de persistência, você teria um correspondente Data Access Object em uma biblioteca diferente. Cada acesso de dados implementa uma interface de objeto e quando um objeto de domínio precisa ter acesso a um método de acesso a dados, ele sempre códigos contra uma interface e nunca contra os próprios DAOs.

No momento, e ainda assim, eu pensei que este projeto muito flexível. No entanto, como a quantidade de objetos no meu modelo de domínio cresceu Eu estou encontrando-me questionando se não é um problema organizacional aqui. Por exemplo, quase todos os objetos no domínio termina com um correspondente Data Access Object e interface de Data Access Object. Não só isso, mas cada um deles está em um lugar diferente, que é mais difícil de manter, se eu quero fazer algo simples como mudança em torno de alguns namespaces.

Curiosamente, muitos desses DAOs (e suas interfaces correspondentes) são criaturas muito simples - o mais comum tem apenas um único método GetById (). Eu acabar com um monte de objetos, como

public interface ICustomerDao {
  Customer GetById(int id);
}

public interface IProductDao {
  Product GetById(int id);
}
public interface IAutomaticWeaselDao {
  AutomaticWeasel GetById(int id);
}

Onde seus implementadores são geralmente muito trivial demais. Isso tem me perguntando se não seria mais simples para ir em uma direção diferente, talvez mudar minha estratégia por ter um único objeto para tarefas de acesso a dados simples, e reservando a criação de acesso a dados dedicado Objetos para aqueles que precisam de algo um pouco mais complicado.

public interface SimpleObjectRepository {
      Customer GetCustomerById(int id);
      Product GetProductById(int id);
      AutomaticWeasel GetAutomaticWeaselById(int id);
      Transaction GetTransactioinById(int id);
}
public interface TransactionDao {
  Transaction[] GetAllCurrentlyOngoingTransactionsInitiatedByASweatyGuyNamedCarl();
}

Alguém tem alguma experiência com uma arquitetura como este? No geral, estou muito feliz com o set-up como é agora a minha única preocupação é a gestão de todos estes pequenos arquivos. Eu ainda estou querendo saber no entanto que as outras abordagens para estruturação da Camada de existir acesso a dados.

Foi útil?

Solução

Eu recomendo contra a abordagem simples que não seja em sistemas simples, geralmente eu acho que sua criação melhor um repositório personalizado para cada agregado e encapsulando tanto a lógica adequada, como você pode dentro dele.

Assim, a minha abordagem seria ter um repositório para cada agregado que precisa dele, como CustomerRepository. Isso teria um Add (Salvar) método e, se adequado para isso, um método remove (Apagar) agregada. Ele também teria quaisquer outros métodos personalizados que se aplicam, incluindo consultas (GetActive) e talvez algumas dessas consultas poderia aceitar especificações.

Isso soa como um grande esforço, mas diferente do costume consulta a maior parte do código é, pelo menos, se você estiver usando um ORM moderno, muito simples de implementar, então eu usar a herança (ReadWriteRepositoryBase onde T: IAggregateRoot) e / ou composição (chamando uma classe RepositoryHelper). A classe base pode ter métodos que se aplicam em todos os casos, como GetById.

Espero que isso ajude.

Outras dicas

Eu trabalho em PHP, mas eu tenho algo conjunto semelhante para minha camada de acesso a dados. Eu tenho implementado uma interface que é algo como isto:

interface DataAccessObject
{
public static function get(array $filters = array(), array $order = array(), array $limit = array());
public function insert();
public function update();   
public function delete();
}

E, em seguida, cada um dos meu acesso a dados objetos trabalho algo como isto:

class DataAccessObject implements DataAccessObject
{
    public function __construct($dao_id = null) // So you can construct an empty object
    {
        // Some Code that get the values from the database and assigns them as properties
    }
    public static function get(array $filters = array(), array $order = array(), array $limit = array()) {};  // Code to implement function
    public function insert() {};  // Code to implement function
    public function update() {};  // Code to implement function 
    public function delete() {};  // Code to implement function        
}

Estou actualmente a construir cada uma das classes de objetos de acesso a dados manualmente, então quando eu adicionar uma tabela ou modificar uma tabela existente no banco de dados, obviamente, eu tenho que escrever o novo código com a mão. No meu caso, isso ainda é um grande passo a partir onde nossa base de código era.

No entanto, você também pode usar os metadados SQL (assumindo que você tem um projeto de banco de dados bastante som que tira proveito das restrições de chave estrangeira e similares) para gerar esses objetos de acesso a dados. Então, em teoria, você poderia usar uma única classe DataAccessObject pai para construir as propriedades e métodos das relações de classe e até mesmo construir para as outras tabelas no banco de dados automaticamente. Isso seria mais ou menos fazer a mesma coisa que você está descrevendo, porque então você pode estender a classe DataAccessObject para fornecer métodos personalizados e propriedades para situações que exigem uma certa quantidade de código construídos manualmente.

Como nota para o desenvolvimento .NET, você já olhou para um quadro que lida com a estrutura subjacente da camada de acesso a dados para você, como Subsonic? Se não, eu recomendaria para apenas tal quadro a: http://subsonicproject.com/ .

Ou para o desenvolvimento PHP, um quadro como o Zend Framework iria fornecer funcionalidade semelhante: http://framework.zend.com

George Eu sei exatamente como você se sente. A arquitetura de Billy faz sentido para mim, mas a necessidade de criar um recipiente, Imapper e arquivos mapeador são painfull. Então, se você estiver usando NHibernate o arquivo .hbm corrosponding e, geralmente, alguns scripts de teste de unidade para verificar tudo está trabalhando.

Eu suponho que mesmo que seu não usando NHibernate o seu ainda estiver usando uma classe base de carga lo genérico / Salvar seus recipientes ou seja

public class BaseDAO<T> : IDAO<T> 
{
     public T Save(T entity)
     { 
       //etc......
     }
}
public class YourDAO : BaseDAO<YourEntity>
{
}

Eu acho que sem NHibernate você estaria usando a reflexão ou alguma outra machanism para determinar o que SQL / SPROC a chamada?

Eitherway, o meu pensamento sobre isso seria onde DAO só precisa executar as operações CRUD básicos definidos na classe base, então não deve haver necessidade de mapeadores personalizados escrever e interfaces. A única maneira que eu posso pensar achiving isso é usar Reflection.Emit para criar dinamicamente o DAO na mosca.

Eu também estou usando o repositório padrão para o meu DAO e estou muito feliz com isso. Sim, você acabar com algumas turmas pequenas, mas é muito fácil de manter. É um pouco mais poderoso se você usar a interface IQueriable (LINQ). Você também pode usar os genéricos (algo como T GetById<T>(int id)) Se você tem uma estrutura de banco de dados bastante consistente.

O sorteio principal de volta para a segunda abordagem está em testes de unidade - zombando fora métodos de fábrica grandes como o seu SimpleObjectRepository requer mais trabalho do que zombando fora apenas ICustomerDao. Mas, meu projeto vai com a segunda abordagem para objetos altamente relacionados (onde a maioria vai ser usado em qualquer testes de unidade), porque ele alivia a carga mental e faz com que seja mais sustentável.

Eu descobrir o que torna o sistema mais sustentável e fácil de entender e fazer isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top