Dołącz/gdzie z LINQ i Lambda

Mam problem z zapytaniem napisanym w LINQ i Lambda. Jak na razie dostaję dużo błędów Oto Mój kod:

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 });

Jestem nowy w używaniu LINQ, więc nie jestem pewien, czy to zapytanie jest poprawne.

Author: BartoszKP, 2010-05-04

9 answers

Uważam, że jeśli znasz składnię SQL, używanie składni zapytań LINQ jest o wiele jaśniejsze, bardziej naturalne i ułatwia wykrywanie błędów:

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 };

Jeśli jednak nadal używasz lambda, twoja składnia jest trochę nieaktualna. Oto to samo zapytanie, używając metod rozszerzenia 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
 750
Author: Daniel Schaffer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-27 15:41:51

Można to zrobić na dwa sposoby. Używając LINQPad (jeśli jesteś nowy w LINQ) i atrapy bazy danych, zbudowałem następujące zapytania:

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

Lub

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

W tym konkretnym przypadku, myślę, że składnia LINQ jest czystsza(zmieniam między nimi w zależności od tego, która jest najłatwiejsza do odczytania).

Chciałbym jednak zwrócić uwagę na to, że jeśli masz odpowiednie klucze obce w swojej bazie danych (między postem a post_meta), prawdopodobnie nie potrzebujesz jawne dołączenie, chyba że próbujesz załadować dużą liczbę rekordów. Twój przykład wydaje się wskazywać, że próbujesz załadować pojedynczy post i są to metadane. Zakładając, że dla każdego posta jest wiele rekordów post_meta, możesz wykonać następujące czynności:

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

Jeśli chcesz uniknąć problemu n + 1, możesz wyraźnie powiedzieć LINQ do SQL, aby załadował wszystkie powiązane elementy za jednym zamachem(chociaż może to być zaawansowany temat, gdy jesteś bardziej zaznajomiony z L2S). Poniższy przykład mówi "kiedy ładujesz Post, ładuj również wszystkie jego rekordy związane z nim za pomocą klucza obcego reprezentowanego przez właściwość '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

Możliwe jest wykonywanie wielu wywołań LoadWith na jednym zestawie DataLoadOptions dla tego samego typu lub wielu różnych typów. Jeśli robisz to często, możesz po prostu rozważyć buforowanie.

 58
Author: Damian Powell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-04 18:27:28

Twoje selektory kluczy są nieprawidłowe. Powinny one wziąć obiekt typu danej tabeli i zwrócić klucz do użycia w połączeniu. Chyba masz na myśli to:

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

Klauzulę where można zastosować później, a nie jako część selektora klawiszy.

 31
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-04 18:23:16

Daniel ma dobre wyjaśnienie zależności składniowych, ale poskładałem ten dokument dla mojego zespołu, aby ułatwić im zrozumienie. Mam nadzieję, że to komuś pomożeTutaj wpisz opis obrazka

 19
Author: Talspaugh27,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-18 12:30:16

Posting ponieważ kiedy zacząłem LINQ + EntityFramework, patrzyłem na te przykłady przez jeden dzień.

Jeśli używasz EntityFramework i masz właściwość nawigacyjną o nazwie {[2] } na skonfigurowanym obiekcie modelu Post, jest to łatwe. Jeśli używasz encji i nie masz tej właściwości nawigacji, na co czekasz?

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

Jeśli najpierw robisz kod, skonfigurujesz właściwość w ten sposób:

class Post {
  [Key]
  public int ID {get; set}
  public int MetaID { get; set; }
  public virtual Meta Meta {get; set;}
}
 5
Author: Visser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-09 03:15:23

Zrobiłem coś takiego;

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);
 3
Author: Mahib,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-09 01:13:43

To może być coś w rodzaju

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};
 2
Author: pepitomb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-22 13:25:42

To zapytanie linq powinno działać dla Ciebie. Dostanie cały post, który ma meta post.

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 });

Równoważne zapytanie SQL

Select * FROM Posts P
INNER JOIN Post_Metas pm ON pm.postId=p.postId
 0
Author: Ahamed Ishak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-22 18:27:07

1 równa się 1 dwa różne połączenia tabel

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 };
 0
Author: mtngunay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-16 20:41:29