O paradigma orientado a objetos é o padrão para o software aplicativo. DBMS relacional - um padrão para armazenar dados em software aplicativo. Sim, você pode escrever no Haskell e armazenar dados exclusivamente no ClickHouse. Mas é sobre o mainstream.
O ORM permite que você
puxe uma coruja em um globo para fingir que não há RDBMS e os dados são armazenados em um modelo de objeto mais adequado para OOP. Permanece um problema "pequeno" - essa abstração, como muitas outras, "flui". Onde no modelo de objeto há um link para outro objeto na chave estrangeira e no ID do banco de dados. No momento da materialização da entidade, somos confrontados com uma escolha:
- Baixe tudo e fique sem memória / tempo limite
- Indique explicitamente quais dependências queremos baixar e quais não, e viole o princípio tell don't ask
- Carregue dependências implicitamente sob demanda usando o Lazy Load e obtenha problemas de desempenho em algum lugar do código chamado
Que tipo de perna você deve cortar: esquerda ou direita?
O TLDR Lazy Load não é tão ruim se usado apenas para gravação e não usado na leitura. Mas nem tudo é tão simples e existem muitas nuances.Com o tempo, cheguei à conclusão de que o Lazy Load e / ou a dependência de entidades na implementação do ORM é o mal menor sob certas condições.
No subsistema de leitura, sempre leia apenas DTO
Em 90% dos casos, os problemas com o Lazy Load surgem precisamente ao ler. Nós obtemos a lista de entidades, examinamos e fazemos um loop e começamos a selecionar todos os dados necessários. Recebemos um monte de consultas no banco de dados. Nesse caso, na maioria das vezes, a única coisa que precisa ser feita é obter os dados, serializá-los e enviá-los de volta no formato JSON. Por que, então, carregar entidades? Não há necessidade de adicionar esses dados ao UOW do rastreador de alterações, para ler toda a entidade, juntamente com os campos "extras". Em vez disso, você sempre pode escrever
Select
ou
ProjectTo
. O Lazy Load não é necessário porque o código C # de
Select
será convertido em SQL e executado no lado do banco de dados.
E se minha lógica não se traduzir para SQL?
Eu recomendo manter a
Avaliação do Cliente desativada. Primeiramente, você pode "ajudar" e adicionar suporte para as funções necessárias
diretamente no sub . Não é uma má opção quando se trata de computação simples, não de regras de negócios. Opção número dois: extraia a interface da entidade e implemente-a na entidade e no DTO.
Por exemplo, no banco de dados existem dois campos: "preço sem desconto" e "preço com desconto". Se o campo "preço com desconto" estiver preenchido, use-o; caso contrário, use o campo com o preço usual. Adicione mais uma regra. Ao comprar 3 produtos, você paga apenas pelos 2 mais caros, enquanto descontos regulares também são levados em consideração.
A implementação pode ser a seguinte:
public interface IHasProductPrice { decimal BasePrice { get; } decimal? SalePrice { get; } } public class Product: IHasProductPrice {
No subsistema de gravação, Lazy Load não é tão assustador
No subsistema de gravação, pelo contrário, muitas vezes apenas o ID para gravação não é suficiente. Todos os tipos de verificações geralmente fazem você ler a entidade inteira, porque o paradigma do objeto envolve a combinação de dados e operações neles no objeto de classe e em seu invariante. Se o projeto usa DDD, as operações de gravação / alteração devem ser executadas através da raiz de agregação e, portanto, apenas sobre um objeto e suas dependências. Um grande número de consultas pode ocorrer apenas ao trabalhar com coleções relacionadas.
Coleções associadas em agregados
Se houver muitos dados na máquina, isso pode indicar um problema de design. Raízes típicas da agregação - cesta, pedido, embalagem. As pessoas geralmente não trabalham com dados de milhares de linhas; portanto, o download de toda a coleção vinculada pode não ser a operação mais produtiva, mas não mortal. Mas se houver milhares de objetos na coleção, é possível que realmente não exista essa raiz de agregação e os desenvolvedores a tenham criado, porque era muito simples fazer isso usando ferramentas improvisadas.
E se ainda houver milhares de registros no agregado?
Passe o
DbContext
ao
construtor e leia apenas os dados necessários no contexto da operação. Sim, viole o DIP. Ou isso, ou não use a unidade nesse caso.
Operações em massa
A importação de um arquivo de 10.000 linhas é um ótimo alvo para o Lazy Load. Aqui, para todos os problemas do subsistema de leitura, os freios do ChangeTracker também são adicionados. Para gravação em massa, você precisa usar
ferramentas separadas. Eu prefiro as extensões de lote, porque novamente você pode fazer sem criar entidades. Para casos especialmente graves, existem bons procedimentos armazenados antigos e até
ferramentas especiais de DBMS .
Life hack
Se você precisar implementar uma operação em massa e uma convencional, precisará começar com uma operação em massa. Uma operação normal é apenas um caso especial de código de massa em uma sequência com apenas um elemento.