Pergunta

Como eu aprender mais e mais sobre OOP, e começar a implementar vários padrões de design, que eu continuo voltando para casos onde as pessoas estão odiando a O Active Record.

Muitas vezes, as pessoas dizem que ele não escala bem (citando o Twitter como principal exemplo) - mas ninguém realmente explica por ele não escala bem;e / ou como alcançar os prós do AR sem o cons (através de um semelhante, mas diferente padrão?)

Espero que isso não se transformar em uma guerra santa sobre padrões de projeto -- tudo o que eu quero saber é ****especificamente**** o que há de errado com Registro Ativo.

Se ele não escala bem, por que não?

Que outros problemas ele tem?

Foi útil?

Solução

ActiveRecord o Padrão de Design e ActiveRecord do Rails Biblioteca ORM, e há também uma tonelada de knock-offs para .NET, e outras línguas.

Todas estas são coisas diferentes.Eles, na sua maioria, que o padrão de design, mas estendem-se e modifica-lo de muitas maneiras diferentes, então antes que alguém diz "ActiveRecord Chupa" ele precisa ser qualificado, dizendo: "que o ActiveRecord, há montes?"

Eu só estou familiarizado com o Rails' ActiveRecord, eu vou tentar abordar todas as denúncias que têm sido levantadas no contexto de usá-lo.

@BlaM

O problema que eu vejo com Registros Ativos é, que é sempre apenas uma tabela

Código:

class Person
    belongs_to :company
end
people = Person.find(:all, :include => :company )

Isso gera SQL com LEFT JOIN companies on companies.id = person.company_id, e gera automaticamente associados Empresa de objetos para que você possa fazer people.first.company e ele não precisa acessar o banco de dados porque os dados já estão presentes.

@pix0r

O problema inerente com o Active Record é que as consultas de banco de dados são gerados automaticamente e executados para preencher objetos e modificar registros do banco de dados

Código:

person = Person.find_by_sql("giant complicated sql query")

Este é desencorajado, como é feio, mas para os casos em que pura e simplesmente precisa escrever matérias SQL, isso é fácil.

@Tim Sullivan

...e você selecionar várias instâncias do modelo, você está basicamente fazendo um "select * from ..."

Código:

people = Person.find(:all, :select=>'name, id')

Isto irá selecionar apenas o nome e a IDENTIFICAÇÃO colunas do banco de dados, todos os outros "atributos" na mapeada objetos só vai ser nulo, a menos que você recarregar manualmente o objeto, e assim por diante.

Outras dicas

Eu sempre achei que o ActiveRecord é bom para a rápida CRUD baseado em aplicações onde o Modelo é relativamente simples (como, não um monte de hierarquias de classe).No entanto, para aplicações complexas, OO hierarquias, uma DataMapper é provavelmente a melhor solução.Enquanto o ActiveRecord, assume uma proporção de 1:1 entre as tabelas e seus dados de objectos, que tipo de relação se torna muito pesado, com mais complexos domínios.Em sua livro sobre padrões de, Martin Fowler destaca que o ActiveRecord, tende a quebrar sob condições onde o Modelo é bastante complexo, e sugere uma DataMapper como alternativa.

Eu encontrei este para ser verdade na prática.Em casos, onde você tem um monte de herança em seu domínio, é mais difícil para o mapa de herança para seu RDBMS que é mapa de associações ou composição.

A maneira que eu faço é ter o "domínio" de objetos que são acessados por seus controladores através destas DataMapper (ou "camada de serviço") classes.Estes não diretamente espelho de banco de dados, mas agir como seu OO representação de algum objeto do mundo real.Digamos que você tenha uma classe de Usuário em seu domínio, e precisa ter referências, ou de coleções de outros objetos, já carregado quando você recuperar o objeto de Usuário.Os dados podem ser provenientes de muitas tabelas diferentes, e um ActiveRecord padrão pode torná-lo muito difícil.

Em vez de carregar o objeto de Usuário diretamente e acesso a dados usando o ActiveRecord estilo API, o controlador de código obtém um objeto de Usuário chamando a API do UserMapper.getUser() método, por exemplo.É que o mapeador de que é responsável por carregar objetos associados a partir de suas respectivas tabelas e retornando concluído Usuário "domínio" o objeto para o chamador.

Essencialmente, você está apenas adicionando outra camada de abstração para tornar o código mais gerenciáveis.Se o DataMapper classes contêm matérias SQL personalizada, ou chamadas para uma camada de abstração de dados API, ou até mesmo acessar um ActiveRecord padrão em si, realmente não importa para o controlador de código que está recebendo um bom, preenchido objeto de Usuário.

De qualquer maneira, é assim que eu faço.

Eu acho que há uma probabilidade de um conjunto muito diferente de razões entre por que as pessoas são "odiar" no ActiveRecord e o que é "errado" com ele.

No odiando problema, há um monte de veneno para nada Trilhos relacionados.Na medida que há de errado com isso, é provável que ela é, como toda a tecnologia e há situações em que é uma boa escolha e situações onde há escolhas melhores.A situação onde você não consegue tirar partido das funcionalidades do Rails, o ActiveRecord, na minha experiência, é onde o banco de dados está mal estruturado.Se estiver a aceder a dados sem chaves primárias, com as coisas que violem a primeira forma normal, onde existem muitos procedimentos armazenados necessários para acessar os dados, você é melhor fora de usar algo que é mais do que apenas um SQL wrapper.Se seu banco de dados é relativamente bem estruturado, o ActiveRecord permite que você tire proveito disso.

Para adicionar o tema de responder aos comentaristas que dizem que as coisas são difíceis no ActiveRecord com um trecho de código a tréplica

@Sam McAfee Digamos que você tenha uma classe de Usuário em seu domínio, e precisa ter referências, ou de coleções de outros objetos, já carregado quando você recuperar o objeto de Usuário.Os dados podem ser provenientes de muitas tabelas diferentes, e um ActiveRecord padrão pode torná-lo muito difícil.

user = User.find(id, :include => ["posts", "comments"])
first_post = user.posts.first
first_comment = user.comments.first

Usando a opção incluir, ActiveRecord permite que você substitua o padrão do carregamento lento de comportamento.

Minha longa e atrasada de resposta, não é mesmo completa, mas uma boa explicação do PORQUÊ eu odeio esse padrão, opiniões e até mesmo algumas emoções:

1) versão curta:O Active Record, cria-se umacamada fina"de "forte ligação"entre a base de dados e o código do aplicativo.O que resolve sem lógica, sem qualquer problemas, sem problemas em tudo.IMHO, ele não fornece QUALQUER VALOR, exceto alguns um açúcar sintático para o programador (que pode, em seguida, usar uma "sintaxe de objeto" para o acesso a alguns dados, que existe em um banco de dados relacional).O esforço para criar um pouco de conforto para os programadores devem (IMHO...), é melhor ser investido em baixo nível de banco de dados de ferramentas de acesso, por exemplo,algumas variações do simples, fácil, simples hash_map get_record( string id_value, string table_name, string id_column_name="id" ) e métodos semelhantes (é claro, os conceitos de elegância e muito varia de acordo com a linguagem utilizada).

2) versão longa:Em qualquer banco de dados orientado a projetos, onde eu tinha o "conceitual" controle das coisas, eu evitava o AR, e isso era bom.Eu costumo criar um arquitetura em camadas (você, mais cedo ou mais tarde dividir o software em camadas de, no mínimo, de médio a grande porte, projetos):

A1) o próprio banco de dados, tabelas, relações, até mesmo um pouco de lógica, se o DBMS permite que ele (o MySQL também é crescido agora)

A2), muitas vezes, não é mais do que um repositório de dados:sistema de arquivos (blobs no banco de dados não são sempre uma boa decisão...), sistemas legados (imagine-se em "como" eles serão acessados, muitas variedades possíveis..mas isso não é o ponto...)

B) banco de dados (camada de acesso a este nível, a ferramenta de métodos auxiliares para acessar facilmente os dados no banco de dados são muito bem-vindos, mas o AR não fornece qualquer valor aqui, com exceção de alguns açúcar sintático)

C) aplicação de camada de objetos:"objetos" às vezes são simples linhas de uma tabela no banco de dados, mas na maioria das vezes eles são composto objetos de qualquer maneira, e ter um pouco mais de lógica ligado, então, investir tempo em AR de objetos, a este nível, é apenas simplesmente inútil, uma perda de preciosos codificadores de tempo, porque o "valor real", o "mais lógica" dos objetos deve ser aplicada na parte superior do AR de objetos, de qualquer maneira - com e sem AR!E, por exemplo, por que você iria querer ter uma abstração do "Registo de entrada de objetos"?A lógica do aplicativo código de escreve-los, mas que deve ter a habilidade de atualizar ou excluí-los?parece bobagem, e App::Log("I am a log message") é algumas ordens de grandeza mais fácil de usar do que le=new LogEntry(); le.time=now(); le.text="I am a log message"; le.Insert();.E, por exemplo:a utilização de um "Registo de entrada objeto" no log de visualizar em seu aplicativo irá funcionar para 100, 1000 ou até 10000 linhas de log, mas, mais cedo ou mais tarde você vai ter que otimizar - e eu aposto que na maioria dos casos, você vai usar apenas esse pequeno bonito instrução SQL SELECT em sua lógica de aplicativo (que totalmente quebra o AR idéia..), em vez de moldagem que pequena declaração rígido e fixo AR idéia quadros com muita código de moldagem e escondendo-o.O tempo desperdiçado com a escrita e/ou a construção de AR código poderia ter sido investido em uma forma muito mais inteligente de interface para leitura de listas de registo de entradas (muitas, muitas maneiras, o céu é o limite).Os codificadores devem atreva-se a inventar novas abstrações para perceber a sua lógica de aplicativo que cabem a aplicação a que se destina, e não é atoa re-implementar padrões de bobo, que som bom à primeira vista!

D) a lógica da aplicação - implementa a lógica de interação de objetos e criação, exclusão e listagem(!) da lógica de aplicação de objetos (NÃO, essas tarefas raramente deve ser ancorada na lógica do aplicativo objetos em si:a folha de papel sobre sua mesa, e dizer-lhe os nomes e as localizações de todas as outras folhas no seu escritório?esqueça o "estático" métodos de listagem de objetos, isso é bobagem, um mau compromisso criado para fazer a forma humana de pensar ajuste em [alguns-não todos-AR-estrutura-como-]RA pensar)

E) a interface de utilizador - bem, o que vou escrever nas linhas seguintes é muito, muito, muito subjetivo, mas na minha experiência, os projetos que construiu no AR, muitas vezes, negligenciado a INTERFACE do usuário parte de um aplicativo de tempo foi desperdiçado na criação obscuro abstrações.No final de tais aplicações desperdiçado uma grande quantidade de codificadores de tempo e sentir-se como aplicações de programadores para programadores, tech-inclinado para dentro e fora.Os codificadores de se sentir bem (trabalho duro, finalmente feito, tudo terminou e correta, de acordo com o conceito de papel...), e os clientes "só tem que aprender que ele precisa para ser assim", porque isso é "profissional"..ok, desculpe, eu discordo ;-)

Bem, na verdade, tudo isso é subjetivo, mas é a minha experiência (Ruby on Rails excluído, ele pode ser diferente, e eu tenho zero de experiência prática com essa abordagem).

Em paga de projetos, muitas vezes eu ouvi a demanda para começar com a criação de alguns "ativo" registro de objetos como um bloco de construção para o nível superior, a lógica da aplicação.Na minha experiência, isso evidentemente, muitas vezes, era algum tipo de desculpa para que o cliente (um software dev empresa, na maioria dos casos) não tem um bom conceito, uma grande visão, uma visão geral do que o produto deve finalmente ser.Os clientes que pensam em rígida quadros ("no projeto há dez anos atrás funcionou bem.."), eles podem carne as entidades, eles podem definir entidades, relações, eles podem quebrar relações de dados e definir básico de lógica de aplicação, mas, em seguida, eles param e entregá-la a você, e acho que isso é tudo o que você precisa...eles, muitas vezes, a falta de um conceito completo de lógica de aplicação, interface do usuário, usabilidade e assim por diante e assim por diante...falta-lhes a grande exibição e falta de amor para os detalhes, e eles querem que você siga de que o AR forma das coisas, porque..bem, por que, ele trabalhou no projeto que anos atrás, ele mantém as pessoas ocupadas e silenciosa?Eu não sei.Mas os "detalhes" separam os homens dos meninos, ou ..como foi o anúncio original slogan ?;-)

Depois de muitos anos (dez anos de desenvolvimento ativo de experiência), sempre que um cliente menciona um "padrão de registro active", o meu alarme campainha toca.Eu aprendi a tentar obtê-los de volta ao essencial concepcionais fase, deixá-los pensar duas vezes, tentar mostrar o seu quadro conceptual fraquezas ou apenas evitá-los se eles estão sem discernimento (no final, você sabe, um cliente que não sabe ainda o que quer, talvez até pensa que sabe, mas não sabe, ou tenta exteriorizar o conceito de trabalho para MIM de graça, custa-me muitas e preciosas horas, dias, semanas e meses do meu tempo, viver é muito curta ...).

Então, finalmente:ISSO TUDO é por que eu odeio essa bobagem "padrão de registro active", e eu faço e vou evitá-lo sempre que possível.

EDITAR:Eu até chamar isso de uma Não-Padrão.Não resolve qualquer problema (padrões não são feitos para criar um açúcar sintático).Ele cria muitos problemas:a raiz de todos os seus problemas (mencionado em muitas respostas aqui..), é que ele apenas esconde o bom e velho bem desenvolvida e poderosa de SQL atrás de uma interface os padrões de definição extremamente limitado.

Este padrão substitui a flexibilidade com açúcar sintático!

Pensar sobre ela, que o problema não AR resolver para você?

Algumas mensagens são de ter me confundido.Algumas respostas estão indo para "ORM" vs "SQL" ou algo parecido.

O fato é que a RA é apenas uma simplificação de programação padrão, onde você tire proveito de seus objetos de domínio para escrever banco de dados de código de acesso.

Esses objetos geralmente têm negócios atributos (propriedades do bean) e alguns comportamentos (métodos que costumam trabalhar com essas propriedades).

O R diz "adicionar alguns métodos para estes objetos de domínio" banco de dados para tarefas relacionadas.

E eu tenho que dizer que, na minha opinião e experiência, o que eu não gosto do padrão.

À primeira vista, pode parecer muito bom.Algumas Java moderna ferramentas como o Spring Roo usa esse padrão.

Para mim, o verdadeiro problema é apenas com OOP preocupação.AR padrão de forças que, de alguma forma, para adicionar uma dependência de seu objeto a infra-estrutura de objetos.Estas infra-estrutura de objectos permitem o domínio do objeto para consulta do banco de dados através de métodos sugeridos pelo AR.

Eu sempre disse que duas camadas são a chave para o sucesso de um projeto.A camada de serviço (onde o bussiness lógica reside ou podem ser exportados através de algum tipo de tecnologia remota, como Web Services, por exemplo) e a camada de domínio.Na minha opinião, se nós adicionamos algumas dependências (não é realmente necessário) para o domínio de camada de objetos para resolver o AR padrão, nossos objetos de domínio será mais difícil para compartilhar com outras camadas ou (raro) aplicações externas.

Spring Roo implementação do AR é interessante, porque ele não depende do objeto em si, mas em alguns AspectJ arquivos.Mas, se mais tarde você não quer trabalhar com o Roo e ter que refatorar o projeto, o AR métodos serão implementados diretamente em seus objetos de domínio.

De outro ponto de vista.Imagine nós não use um Banco de dados Relacional para armazenar nossos objetos.Imagine o aplicativo armazena o nosso domínio de objetos em um Banco de dados NoSQL ou apenas em arquivos XML, por exemplo.Poderíamos implementar os métodos que fazer essas tarefas em nossos objetos de domínio?Eu não acho que isso (por exemplo, no caso de XM, gostaríamos de acrescentar XML relacionados a dependências de nossos objetos de domínio...Realmente triste, eu acho).Por que, então, temos de implementar o relacional, DB de métodos em objetos de domínio, como o Ar padrão diz?

Para resumir, o AR padrão de som mais simples e boa para pequenos e aplicações simples.Mas, quando temos complexos e de grande apps, eu acho que a clássica arquitetura em camadas é a melhor abordagem.

A questão é sobre o Ativo Registro padrão de design.Não um orm Ferramenta.

A pergunta original é marcado com o rails e refere-se ao Twitter, que é construído em Ruby on Rails.O ActiveRecord quadro dentro do Rails é uma implementação de Fowler Registro Ativo padrão de design.

A principal coisa que eu tenho visto com relação às queixas sobre o Active Record é que quando você cria um modelo em torno de uma mesa, e você selecionar várias instâncias do modelo, você está basicamente fazendo um "select * from ...".Isso é bom para a edição de um registro ou a exibição de um registro, mas se você quiser, dizer, mostrar uma lista de cidades para todos os contactos no seu banco de dados, você pode fazer "select Cidade from ..." e só recebem as cidades.Fazendo isso, com o Registro de exigiria que você está selecionando todas as colunas, mas apenas usando Cidade.

É claro, diferentes implementações irá lidar com isso de forma diferente.No entanto, é um problema.

Agora, você pode contornar esse problema criando um novo modelo para a coisa específica que você está tentando fazer, mas algumas pessoas argumentam que é mais esforço do que o benefício.

Mim, eu cavar Registro Ativo.:-)

HTH

Eu amo o jeito Subsónico a uma coluna única coisa.
Ou

DataBaseTable.GetList(DataBaseTable.Columns.ColumnYouWant)

, ou:

Query q = DataBaseTable.CreateQuery()
               .WHERE(DataBaseTable.Columns.ColumnToFilterOn,value);
q.SelectList = DataBaseTable.Columns.ColumnYouWant;
q.Load();

Mas o Linq é ainda o rei quando se trata de carregamento lento.

@BlaM:Às vezes eu justed implementado um registo activo por um resultado de uma associação.Nem sempre tem de ser a relação de Tabela <--> Registro Ativo.Por que não "Resultado de uma instrução Join" <--> O Active Record ?

Eu vou falar sobre o Active Record, como um padrão de design, eu não vi ROR.

Alguns desenvolvedores de ódio Registro Ativo, porque ler inteligente livros sobre como escrever bem limpo e arrumado código, e estes livros informar que o registro ativo viola único resposobility princípio, viola DDD regra de que o objeto de domínio deve ser persistente, ignorante, e muitas outras regras a partir de este tipo de livros.

A segunda coisa objetos de domínio no Active Record tendem a ser de 1 para 1 com banco de dados, que pode ser considerado uma limitação em algum tipo de sistemas (n-tier principalmente).

Isso é apenas o resumo coisas, eu não vi o ruby on rails real implementação deste padrão.

O problema que eu vejo com Registros Ativos é, que é sempre apenas sobre um tabela.Tudo bem, desde que você realmente trabalhar apenas com essa tabela, mas quando você trabalha com dados, na maioria dos casos você vai ter algum tipo de associação em algum lugar.

Sim, participar geralmente é pior do que nenhuma associação em todos os quando se trata do desempenho, mas participar normalmente é melhor do que "falso" join pela primeira leitura a toda a tabela e, em seguida, usando o ganho de informação para leitura e filtro de tabela B.

O problema com o ActiveRecord é que as consultas que gera automaticamente para que você pode causar problemas de desempenho.

Você acaba fazendo algumas intuitivos truques para otimizar as consultas que deixar você se perguntando se ele teria sido mais tempo eficaz para escrever a consulta com a mão em primeiro lugar.

Apesar de todos os outros comentários sobre SQL otimização são certamente válida, a minha principal reclamação com o registo activo padrão é que, geralmente, leva a o descasamento de impedância.Eu gosto de manter o meu domínio limpo e devidamente encapsulado, que o padrão de registro active geralmente destrói toda a esperança de o fazer.

Tente fazer um de muitos para muitos polimórficos relacionamento.Não é tão fácil.Especialmente quando você não estiver usando IST.

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