dataContext.Contents.Where(c =>
!dataContext.ContentToTopicRelations.Any(ctr =>
ctr.ContantId == c.ContentId &&
ctr.TopicId == topicId))
Это идентично select * from Content where not exists(...)
.И в общем случае это лучше, чем левое соединение и проверка на ноль (это зависит от статистики таблицы, но ..), потому что это даст (опять же, в общем случае) полу левое соединение вместо левого соединения (в плане выполнения).
Для самого левого соединения используйте код, подобный следующему (но я рекомендую использовать код, который генерирует not exists
для вашей задачи):
from c in dataContext.Contents
join tempCTR in dataContext.ContentToTopicRelations
on new { c.ContentId, topicId) equals new { tempCTR.ContentId, tempCTR.TopicId }
into tempCTRCollection
from ctr in tempCTRCollection.DefaultIfEmpty()
where ctr == null
select c