forma eficiente de preencher consulta Framework Entify com objetos relacionados?

votos
0

Estou usando EF para um conjunto de objetos e deseja consultar um tipo de objeto com as entradas correspondentes de outras duas tabelas. Esta é para despejar a consulta em uma saída XML. Na primeira, usou uma juntar-se uma vez nos dados originais cada empregado sempre teve 1+ instâncias de um computador objeto (solução # 2 abaixo), mas não é necessariamente verdade.

Para propósito aqui, imagine:

  • um empregado objeto,
  • cada funcionário tem uma EmployeeType (algumas entradas fixas) e
  • Cada funcionário tem de zero ou mais computador objectos (normalmente 0-3).
  • cada computador pertence a um empregado, nem todos Employee tem um computador.
  • cada funcionário tem um critério em que a pesquisa baseia-se (tal como Division ).

Então eu vi várias soluções possíveis:

  1. Use o Employee.Computer.Load () dentro de um loop, mas com mais de 10.000 linhas, que causa uma penalidade de desempenho enorme.

  2. Use uma juntar-se na consulta, mas que deixa de fora todos os empregados que não possuem um computador .

  3. Use Linq to Entities, mas que parece ter a sobrecarga de # 1: ao carregar Computer é que ela atinge o banco de dados para CADA Employee .

  4. Use uma segunda consulta (todo o computador s com correspondência Computer.Employee.Division ), então no Employee loop, adicionar qualquer computador para o empregado dado. Ao implementar isso, eu achei que apenas correr a segunda consulta (com ToList () ) a EF preenche os corretos Employee.Computer listas com os objetos que eu preciso.

Aqui, # 4 carrega os dados com apenas 2 banco de dados atinge em vez de 10k +, eo EntityFramework realmente agrupa os objetos e cria todos os relacionamentos.

Minhas perguntas :

  • Com # 4, é o fato de que a EF preenche o Employee.Computer lista algo em que eu posso confiar? Se assim for, você pode apontar-me a documentação?
  • Existe uma maneira melhor do que # 4?

ATUALIZAÇÃO : Bem, droga. Desculpe, mas eu simplesmente estragou tudo. Eu estava focando o relacionamento com a tabela Computador e perdeu o fato de que eu tinha uma explícita Employee.EmployeeTypeReference.Load () w / o primeiro teste para NULL, então a lista de computador era uma não-questão completa.

Eu só descobri isso quando a execução de alguns testes de desempenho e adicionando solução de Craig à mistura. Na verdade, os registros não são empregados e Computadores, mas abstrações, e I (condicionalmente) incluem todos os campos na saída XML, mas eles são pequenos: um nome, ID (PK) e ID (FK) mais um INT na tabela Employee. Portanto, a minha presunção era que o desempenho seria semelhante desde a EF criaria objetos não muito mais pesados ​​do que a projeção.

De qualquer forma, aqui estão os resultados wher o tempo decorrido foi a diferença antes desta consulta e após o XML resultante foi criado.

  • Caso 1: O mesmo que # 2, mas com Incluir () declarações:

    list = ve.Employee.Include(Computer).Include(EmployeeType).Where(e => e.Division.ID == divId).OrderBy(e => e.Name);

    Decorrido: 4,96, 5,05

  • Caso 2: Usos em linha Load () :

    list = ve.Employee.Where(e => e.Division.ID == divId).OrderBy(e => e.Name);

    Decorrido: 74,62

  • Caso 3: O mesmo que o nº 4, mas com Incluir () declarações:

    list = from e in ve.Employee.Include(Computer).Include(EmployeeType) where e.Division.ID == divId orderby e.Name select e;

    Decorrido: 4,91, 5,47

  • Caso 4: Usos em linha Load () :

    list = from e in ve.Employee where e.Division.ID == divId orderby e.Name select e;

    Decorrido: 74.20

  • Caso 5: Use * Incluir ( EmployeeType) e consulta separada Computer, deixe EF associado:

    elist = ve.Employee.Include(EmployeeType).Where(te => te.Division.ID == divId).OrderBy(e => e.Name).ToList(); alist = ve.Alias.Where(a => a.Employee.Division.ID == divId).ToList();

    Decorrido: 4,50, 4,02

  • Caso 6: sugestão de projeções de Craig:

    elist = from te in ve.ThesaurusEntry where te.Division.ID==divID orderby te.Name select new { ID = te.ID, Name = te.Name, Type = te.EmployeeType.Name, Freq = te.Frequency, Aliases = from a in te.Alias select new { ID = a.ID, Name = a.Name } };

    Decorrido: 0,73, 1,25

conclusões

Load () é caro, por isso uso Incluir () ou pelo menos teste com IsLoaded

Projeção é um pouco tedioso, mas significativamente mais rápido do que EF fix-up. [com este teste limitado em tabelas estreitos]

Publicado 26/08/2009 em 23:16
fonte usuário
Em outras línguas...                            


2 respostas

votos
2

Eu acredito que você pode indicar que as relações podem ser pré-carregado

Dim employees = From emp in db.Employees.Include("Computer") _
                Select emp
Respondeu 27/08/2009 em 01:06
fonte usuário

votos
1

A solução de Rob vai funcionar (+1), mas se você não precisa de todos os campos em, digamos, do empregado e de Computadores, eu fortemente recomendo projetando em vez disso:

var q = from e in Context.Employees
        where e.Division.Id = divisionId
        select new
        {
            Name = e.Name,
            EmployeeType = e.EmployeeType.Description,
            ComputerIds = from c in e.Computers
                          select new 
                          {
                              Id = c.Id
                          }
        };

Aqui você tem tudo que você precisa em uma consulta, mas nada mais : Todos os campos que você não precisa não serão devolvidos.

Você provavelmente poderia até escolher em XElements e apenas salvar a árvore resultante em vez de converter manualmente para XML. Eu não tentei isso, mas parece que ele deve funcionar.

Em relação a # 4, sim, você pode contar com isso, mas é sempre bom verificar IsLoadedantes de chamar Load().

Respondeu 27/08/2009 em 14:17
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more