Junte-se / Onde com LINQ e Lambda

Estou tendo problemas com uma consulta escrita no LINQ e no Lambda. Até agora, estou recebendo muitos erros aqui está o meu código:

int id = 1; var query = database.Posts.Join(database.Post_Metas, post => database.Posts.Where(x => x.ID == id), meta => database.Post_Metas.Where(x => x.Post_ID == id), (post, meta) => new { Post = post, Meta = meta }); 

Eu sou novo em usar o LINQ, então não tenho certeza se essa consulta está correta.

Acho que, se você estiver familiarizado com a syntax SQL, usar a syntax de consulta LINQ é muito mais claro, mais natural e facilita a identificação de erros:

 var id = 1; var query = from post in database.Posts join meta in database.Post_Metas on post.ID equals meta.Post_ID where post.ID == id select new { Post = post, Meta = meta }; 

Se você está realmente preocupado em usar lambdas, sua syntax está um pouco errada. Aqui está a mesma consulta, usando os methods de extensão LINQ:

 var id = 1; var query = database.Posts // your starting point - table in the "from" statement .Join(database.Post_Metas, // the source table of the inner join post => post.ID, // Select the primary key (the first part of the "on" clause in an sql "join" statement) meta => meta.Post_ID, // Select the foreign key (the second part of the "on" clause) (post, meta) => new { Post = post, Meta = meta }) // selection .Where(postAndMeta => postAndMeta.Post.ID == id); // where statement 

Você poderia ir de duas maneiras com isso. Usando LINQPad (inestimável se você é novo no LINQ) e um database fictício, eu construí as seguintes consultas:

 Posts.Join( Post_metas, post => post.Post_id, meta => meta.Post_id, (post, meta) => new { Post = post, Meta = meta } ) 

ou

 from p in Posts join pm in Post_metas on p.Post_id equals pm.Post_id select new { Post = p, Meta = pm } 

Neste caso em particular, eu acho que a syntax do LINQ é mais limpa (eu mudo entre os dois dependendo de qual é a mais fácil de ler).

A coisa que eu gostaria de salientar é que se você tem foreign keys apropriadas em seu database, (entre post e post_meta) então você provavelmente não precisa de uma junit explícita a menos que esteja tentando carregar um grande número de registros . Seu exemplo parece indicar que você está tentando carregar uma única postagem e seus metadados. Supondo que haja muitos registros post_meta para cada postagem, você pode fazer o seguinte:

 var post = Posts.Single(p => p.ID == 1); var metas = post.Post_metas.ToList(); 

Se você quiser evitar o problema n + 1, você pode explicitamente dizer ao LINQ to SQL para carregar todos os itens relacionados de uma só vez (embora este possa ser um tópico avançado para quando você estiver mais familiarizado com o L2S). O exemplo abaixo diz “quando você carrega um Post, também carrega todos os seus registros associados a ele através da chave estrangeira representada pela propriedade ‘Post_metas'”:

 var dataLoadOptions = new DataLoadOptions(); dataLoadOptions.LoadWith(p => p.Post_metas); var dataContext = new MyDataContext(); dataContext.LoadOptions = dataLoadOptions; var post = Posts.Single(p => p.ID == 1); // Post_metas loaded automagically 

É possível fazer muitas chamadas LoadWith em um único conjunto de DataLoadOptions para o mesmo tipo ou vários tipos diferentes. Se você fizer isso muito, você pode querer apenas considerar o cache.

Seus seletores principais estão incorretos. Eles devem pegar um object do tipo da tabela em questão e retornar a chave para usar na junit. Eu acho que você quer dizer isso:

 var query = database.Posts.Join(database.Post_Metas, post => post.ID, meta => meta.Post_ID, (post, meta) => new { Post = post, Meta = meta }); 

Você pode aplicar a cláusula where posteriormente, não como parte do seletor de chave.

Daniel tem uma boa explicação das relações de syntax, mas eu juntei este documento para a minha equipe, a fim de torná-lo um pouco mais simples para eles entenderem. Espero que isso ajude alguém insira a descrição da imagem aqui

Postagem porque quando eu iniciei o LINQ + EntityFramework, observei esses exemplos por um dia.

Se você estiver usando EntityFramework e tiver uma propriedade de navegação denominada Meta na configuração do object Post model, isso será fácil. Se você está usando entidade e não tem essa propriedade de navegação, o que você está esperando?

 database .Posts .Where(post => post.ID == id) .Select(post => new { post, post.Meta }); 

Se você está fazendo código primeiro, você configuraria a propriedade assim:

 class Post { [Key] public int ID {get; set} public int MetaID { get; set; } public virtual Meta Meta {get; set;} } 

Eu fiz algo assim;

 var certificationClass = _db.INDIVIDUALLICENSEs .Join(_db.INDLICENSECLAsses, IL => IL.LICENSE_CLASS, ILC => ILC.NAME, (IL, ILC) => new { INDIVIDUALLICENSE = IL, INDLICENSECLAsse = ILC }) .Where(o => o.INDIVIDUALLICENSE.GLOBALENTITYID == "ABC" && o.INDIVIDUALLICENSE.LICENSE_TYPE == "ABC") .Select(t => new { value = t.PSP_INDLICENSECLAsse.ID, name = t.PSP_INDIVIDUALLICENSE.LICENSE_CLASS, }) .OrderBy(x => x.name); 

Pode ser algo como

 var myvar = from a in context.MyEntity join b in context.MyEntity2 on a.key equals b.key select new { prop1 = a.prop1, prop2= b.prop1}; 

Esta consulta de linq deve funcionar para você. Ele vai pegar todo o post que tem post meta.

 var query = database.Posts.Join(database.Post_Metas, post => post.postId, // Primary Key meta => meat.postId), // Foreign Key (post, meta) => new { Post = post, Meta = meta }); 

Consulta SQL Equivalente

 Select * FROM Posts P INNER JOIN Post_Metas pm ON pm.postId=p.postId 

1 é igual a uma junit de duas tabelas diferentes

 var query = from post in database.Posts join meta in database.Post_Metas on 1 equals 1 where post.ID == id select new { Post = post, Meta = meta };