ICollection <T> Vs List <T> no Entity Framework

115

Eu assisti apenas alguns webcasts antes de começar a projetar alguns aplicativos do Entity Framework. Eu realmente não li muita documentação e sinto que estou sofrendo por isso agora.

Tenho usado List<T>em minhas aulas e tem funcionado muito bem.

Agora eu li alguma documentação e ela afirma que eu deveria estar usando ICollection<T>. Eu mudei para isso, e nem mesmo causou uma mudança no contexto do modelo. É porque ambos List<T>e ICollection<T>herdam IEnumerable<T>, e isso é o que é realmente necessário para EF?

No entanto, se for esse o caso, por que a documentação da EF não afirma que é necessário em IEnumerable<T>vez de ICollection<T>?

Em qualquer caso, há alguma desvantagem no que fiz ou devo mudá-lo?

wil
fonte

Respostas:

113

O Entity Framework usaria ICollection<T>porque precisa oferecer suporte a Addoperações, que não fazem parte da IEnumerable<T>interface.

Observe também que você estava usando ICollection<T>, apenas expondo-o como a List<T>implementação. List<T>traz junto com ele IList<T>, ICollection<T>e IEnumerable<T>.

Quanto à sua mudança, expor via interface é uma boa escolha, apesar de List<T>funcionar. A interface define o contrato, mas não a implementação. A implementação pode mudar. Em alguns casos, talvez a implementação possa ser um HashSet<T>, por exemplo. (Esta é uma mentalidade que você pode usar para mais do que apenas Entity Framework, a propósito. Uma boa prática orientada a objetos é programar para a interface e não para a implementação. As implementações podem e irão mudar.)

Anthony Pegram
fonte
2
Então ... só para eu entender um pouco mais - List herda IList, que herda ICollection, que herda IEnumerable?
wil
3
Sim, essa é a cadeia. List<T>tem de implementar cada uma dessas interfaces ( IList<T>, ICollection<T>, IEnumerable<T>) por causa da hierarquia de herança. Para completar, IList<T>também pega os não-genéricos IList, ICollectione IEnumerableinterfaces.
Anthony Pegram,
Obrigado ... Algumas das características do Ixxx ainda escapam ao meu entendimento! Você entendeu, no entanto, uma última coisa que está me incomodando: se o outro Ixx herda IEnumerable, como isso aumenta o IEnumerable se um Ienumerable é somente leitura? ... Se for muito complexo, não se preocupe, quando eu tiver um tempinho, tentarei acionar o refletor!
wil
10
As operações normais do Linq não adicionam ou alteram coisas, elas simplesmente filtram, agrupam, projetam, etc. Sequências somente de avanço e somente leitura são tudo o que é necessário para suportar essas operações. Quando você tem um provedor Linq como o Entity Framework que lida com persistência de dados, a capacidade de adicionar é um benefício substancial que requer uma interface mais robusta, que é o que convida ICollection<T>à festa (e essa interface traz consigo IEnumerable<T>, então o "normal "As operações do Linq ainda são válidas).
Anthony Pegram,
@AnthonyPegram: Acho que é estritamente incorreto dizer que todas as três interfaces devem ser implementadas. Visto que IList <T> herda ICollection <T> que herda IEnumerable <T>, é suficiente para List <T> simplesmente implementar IList <T>.
CJ7
51

Eles escolheram a interface que escolheram porque ela oferece uma abstração compreensível sobre as consultas mágicas que o Entity Framework realiza quando você usa o Linq.

Aqui está a diferença entre as interfaces:

  • IEnumerable<T> é somente leitura
  • Você pode adicionar e remover itens de um ICollection<T>
  • Você pode fazer acesso aleatório (por índice) a um List<T>

Destes, ICollectione IEnumerablemapear bem para operações de banco de dados, uma vez que consultar e adicionar / remover entidades são coisas que você pode fazer em um banco de dados.

O acesso aleatório por índice não mapeia tão bem, já que você teria que ter um resultado de consulta existente para iterar, ou cada acesso aleatório consultaria o banco de dados novamente. Além disso, o que o índice mapearia? Número da linha? Não há muitas consultas de número de linha que você gostaria de fazer e não é de forma alguma útil na construção de consultas maiores. Então, eles simplesmente não apóiam isso.

ICollection<T> é compatível e permitirá que você consulte e altere dados, então use isso.

O motivo pelo qual List<T>funciona para começar é porque a implementação do EF acaba retornando um no final. Mas isso está no final de sua cadeia de consultas, não no início. Portanto, fazer suas propriedades ICollection<T>tornará mais óbvio que o EF cria um monte de SQL e só retorna a List<T>no final, em vez de fazer consultas para cada nível de Linq que você usa.

Merlyn Morgan-Graham
fonte
8

ICollection difere de IEnumerable porque você pode adicionar itens à coleção, enquanto com IEnumerable você não pode. Portanto, em suas classes POCO, por exemplo, você deseja usar ICollection se pretende permitir que a coleção seja adicionada. Torne o ICollection virtual para se beneficiar do carregamento lento também.

Ralph Lavelle
fonte
1
Eu quero entender - você pode fazer as mesmas operações (e muito mais!) Com List <T>. Por que ICollection <T>? Por que não Listar <T>? Parece mais simples e mais poderoso.
monstro de
List <T> Implementa ICollection e IEnumerable. Mais operação, mas com isso vem mais sobrecarga.
IronAces
4

Embora a questão tenha sido postada anos atrás, ela ainda é válida quando alguém está procurando o mesmo cenário.

Há um artigo recente do CodeProject [2015] que explica a diferença em muitos detalhes e representação gráfica com código de amostra . Não está focado diretamente na EF, mas ainda espero que seja de maior ajuda:

List vs IEnumerable vs IQueryable vs ICollection vs IDictionary

BiLaL
fonte