Você poderia seguir dois caminhos com isso. Usando o LINQPad (inestimável se você é novo no LINQ) e um banco de dados fictício, criei 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 }
Nesse caso em particular, acho que a sintaxe do LINQ é mais limpa (alterno entre os dois, dependendo do que é mais fácil de ler).
O que eu gostaria de salientar é que, se você possui chaves estrangeiras apropriadas em seu banco de dados (entre post e post_meta), provavelmente não precisará de uma associação 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ê deseja evitar o problema n + 1, pode dizer explicitamente ao LINQ to SQL para carregar todos os itens relacionados de uma só vez (embora esse possa ser um tópico avançado para quando você estiver mais familiarizado com o L2S). O exemplo abaixo diz "quando você carrega uma postagem, também carrega todos os seus registros associados a ela por meio da chave estrangeira representada pela propriedade 'Post_metas'":
var dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Post>(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 várias LoadWith
chamadas em um único conjunto DataLoadOptions
para o mesmo tipo ou vários tipos diferentes. Se você fizer isso muito, porém, considere apenas o cache.