С# присоединяется/где с Linq и Lambda
У меня возникают проблемы с запросом, написанным в Linq и Lambda. До сих пор у меня появилось много ошибок в моем коде:
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 });
Я новичок в использовании Linq, поэтому я не уверен, правильно ли этот запрос.
Ответы
Ответ 1
Я нахожу, что если вы знакомы с синтаксисом SQL, использование синтаксиса запроса LINQ намного яснее, более естественным и облегчает обнаружение ошибок:
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 };
Если вы действительно застряли в использовании lambdas, ваш синтаксис довольно немного. Здесь тот же запрос, используя методы расширения 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
Ответ 2
Вы можете пойти двумя способами с этим. Используя LINQPad (неоценимый, если вы новичок в LINQ) и фиктивная база данных, я построил следующие запросы:
Posts.Join(
Post_metas,
post => post.Post_id,
meta => meta.Post_id,
(post, meta) => new { Post = post, Meta = meta }
)
или
from p in Posts
join pm in Post_metas on p.Post_id equals pm.Post_id
select new { Post = p, Meta = pm }
В этом конкретном случае я думаю, что синтаксис LINQ более чист (я изменяю между ними в зависимости от того, что проще всего читать).
То, что я хотел бы отметить, состоит в том, что если у вас есть соответствующие внешние ключи в вашей базе данных (между post и post_meta), вам, вероятно, не требуется явное соединение, если вы не пытаетесь загрузить большой количество записей. Ваш пример показывает, что вы пытаетесь загрузить одну запись и метаданные. Предполагая, что для каждого сообщения есть много записей post_meta, вы можете сделать следующее:
var post = Posts.Single(p => p.ID == 1);
var metas = post.Post_metas.ToList();
Если вы хотите избежать проблемы n + 1, вы можете явно указать LINQ to SQL для загрузки всех связанных элементов за один раз (хотя это может быть расширенная тема, когда вы более знакомы с L2S), В приведенном ниже примере говорится "когда вы загружаете сообщение, также загружаете все свои записи, связанные с ним, через внешний ключ, представленный свойством" 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
Можно сделать много вызовов LoadWith
для одного набора DataLoadOptions
для одного и того же типа или для разных типов. Если вы делаете это много, вы можете просто рассмотреть вопрос о кешировании.
Ответ 3
Ваши селекторы клавиш неверны. Они должны взять объект типа рассматриваемой таблицы и вернуть ключ для использования в соединении. Я думаю, вы имеете в виду это:
var query = database.Posts.Join(database.Post_Metas,
post => post.ID,
meta => meta.Post_ID,
(post, meta) => new { Post = post, Meta = meta });
Вы можете применить предложение where впоследствии, а не как часть селектора клавиш.
Ответ 4
Даниэль имеет хорошее объяснение синтаксических отношений, но я поставил этот документ вместе для своей команды, чтобы сделать его немного проще для понимания. Надеюсь, это поможет кому-то ![введите описание изображения здесь]()
Ответ 5
Проводка, потому что, когда я начал LINQ + EntityFramework, я смотрел на эти примеры в течение дня.
Если вы используете EntityFramework и у вас есть свойство навигации с именем Meta
на вашем объекте модели Post
, это очень просто. Если вы используете сущность и не имеете этого свойства навигации, чего вы ждете?
database
.Posts
.Where(post => post.ID == id)
.Select(post => new { post, post.Meta });
Если вы сначала выполняете код, вы должны установить свойство таким образом:
class Post {
[Key]
public int ID {get; set}
public int MetaID { get; set; }
public virtual Meta Meta {get; set;}
}
Ответ 6
Это может быть что-то вроде
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};
Ответ 7
Этот запрос linq должен работать на вас. Он получит всю почту, в которой есть мета-сообщение.
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 });
Эквивалентный SQL-запрос
Select * FROM Posts P
INNER JOIN Post_Metas pm ON pm.postId=p.postId
Ответ 8
Я сделал что-то вроде этого:
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);