Pergunta

Como você preguiçosos listas aninhadas sem realmente executar a consulta? Usando um exemplo muito básico, digamos que eu tenha:

class CityBlock {
     IList<Building> BuildingsOnBlock;
     Person BlockOwner;
}

class Building {
     IList<Floor> FloorsInBuilding;
}

class Floor {
     IList<Cubicle> EmployeeCubicles;
}

Class Cubicle {
     System.Guid CubicleID;
     Person CubicleOccupant;
}

E então, na minha camada de repositório, tenho o seguinte método:

GetCityBlocks()

E então, na camada de serviço, terei GetCityBlocksByowner, onde utilizo um método de extensão para obter os blocos da cidade de propriedade de uma pessoa específica, diz que queremos apenas os blocos da Guido:

GetCityBlocks().ForOwner("Guido")

Se fizermos um .tolist () no repositório, ele vai executar as perguntas - isso será ridículo, pois não sabemos quem está chegando nesse nível. Então, a questão é: como fazemos isso com eficiência?

Vamos supor que haja 50000 proprietários de blocos e cerca de 1000000 blocos da cidade, carregar todos eles não é uma opção. Usar iQueryables não funcionará devido ao ninho (sem hackers extremos, pelo menos que eu conheço). Além disso, se eu tentar usar algo como o Lazylist de Rob Conery, essencialmente temos um vazamento do nosso DAL para nossos modelos de domínio, o que pode ser muito ruim no futuro.

Então, como faço para fazer isso corretamente?

  • É uma questão de determinar o contexto correto? Nesse caso, faríamos isso na camada do repositório ou na camada de serviço?
  • Eu me fundi pela camada de serviço e minha camada de repositório para obter métodos de serviço muito específicos?
  • Ou estou perdendo algo completamente? (ainda relativamente novo para a coisa do Linq2SQL, que está sendo eliminada de qualquer maneira ...)

Editar:No padrão do repositório, estamos atualmente mapeando para nossos objetos de domínio, para que pareça algo assim:

public IQueryable<CityBlock> GetCityBlocks(){
    var results = from o in db.city_blocks
                  let buildings = GetBuildingsOnBlock(o.block_id)
                  select new CityBlock {
                      BuildingsOnBlock = buildings,
                      BlockOwner = o.block_owner
                  };
    return results;
}

Para que isso funcione, teríamos que fazer com que os edifícios obtenham um .tolist (), a menos que façamos esse campo real no objeto da cidade um iQueryable - o que não parece certo, porque parece que muito poder seria Concedido a qualquer pessoa que acesse o CityBlock.BuildingSonBlock Field. Isso está mapeando para nossos objetos de domínio algo que talvez devamos fazer na camada de serviço?

Foi útil?

Solução

Você faz isso retornando iQueryables em vez de ilistas.

Tolist () faz com que as consultas sejam executadas imediatamente, porque uma conversão deve ser realizada de iQueryable para ilist.

Desde que você retorne os iQueryables Lazy, o carregamento deve adiar a execução até que os dados sejam realmente necessários, ou seja, quando Tolist () é chamado.

Não consigo encontrar uma referência no momento, mas é meu entendimento de que, se você fizer isso dessa maneira, o LINQ para SQL tem a oportunidade de otimizar o SQL que ele envia para o servidor. Em outras palavras, ele finalmente lerá estes registros:

GetCityBlocks().ForOwner("Guido")

Em vez de esses registros:

GetCityBlocks()

Outras dicas

Você pode tentar uma abordagem diferente para mapear seus objetos de domínio para fazê -lo funcionar. O problema é que, não importa o que você faça (a menos que você altere suas listas para iQueryables em seus objetos de domínio), você acabará por toler () enquanto está mapeando.

Para outra maneira, permitir que o LINQ2SQL faça o mapeamento para os seus PoCos, criando um datacontext personalizado e não usando o designer para o mapeamento :), assim você mantém seu modelo de domínio limpo e deixe o Linq2SQL preencher as dependências no momento correto. Observe que entrar nessa rota tem seus próprios problemas, mas pode ser feito.

Aqui está um link para você começar nesta rota

Alcançando poco s em linq para sql

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