Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
join A záradék segítségével különböző forrásütemezésekből származó elemeket társíthat, amelyek nem rendelkeznek közvetlen kapcsolatokkal az objektummodellben. Az egyetlen követelmény az, hogy az egyes forráselemeknek legyen egy olyan értéke, amelyet összehasonlíthat az egyenlőség szempontjából. Egy élelmiszer-forgalmazó például rendelkezhet egy bizonyos termék szállítóinak listájával és a vásárlók listájával. Záradék használatával join létrehozhatja a termék szállítóinak és vevőinek listáját, akik mind ugyanabban a meghatározott régióban találhatók.
A C# nyelv referenciadokumentuma a C# nyelv legújabb kiadású verzióját ismerteti. Emellett a közelgő nyelvi kiadás nyilvános előzetes verziójú funkcióinak kezdeti dokumentációját is tartalmazza.
A dokumentáció azonosítja azokat a funkciókat, amelyeket először a nyelv utolsó három verziójában vagy az aktuális nyilvános előzetes verziókban vezetnek be.
Jótanács
Ha meg szeretné tudni, hogy mikor jelent meg először egy funkció a C#-ban, tekintse meg a C# nyelvi verzióelőzményeiről szóló cikket.
A join kifejezés bemenetként két forrásszekvenciát használ. Az egyes sorozatok elemeinek olyan tulajdonságnak kell lenniük vagy tartalmazniuk, amelyet összehasonlíthat a másik sorozat megfelelő tulajdonságával. A join záradék a speciális equals kulcsszóval hasonlítja össze a megadott egyenlőségi kulcsokat. A záradék által végrehajtott összes illesztés join egyenrangú. A záradék kimenetének join alakja az éppen végrehajtott illesztés típusától függ. Az alábbi lista a három leggyakoribb illesztéstípust mutatja be:
- Belső illesztés
- Csoporthoz való csatlakozás
- Bal oldali külső illesztés
Belső illesztés
Az alábbi példában egy egyszerű belső egyenrangúság látható. Ez a lekérdezés a "terméknév/ kategória" párok egybesimított sorozatát hozza létre. Ugyanaz a kategóriasztring több elemben is megjelenik. Ha egy elemnek categories nincs egyezője products, az a kategória nem jelenik meg az eredmények között.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence
További információért lásd: Belső illesztések végrehajtása.
Csoporthoz való csatlakozás
A join kifejezéssel rendelkező into záradékot csoportos összekapcsolásnak nevezzük.
var innerGroupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new { CategoryName = category.Name, Products = prodGroup };
A csoportillesztés hierarchikus eredményütemezést hoz létre, amely a bal oldali forrásütemezés elemeit társítja a jobb oldali forrásütemezés egy vagy több egyező eleméhez. A csoportillesztés relációs értelemben nem egyenértékű; lényegében objektumtömbök sorozata.
Ha a jobb forrásütemezés egyik eleme sem egyezik meg a bal oldali forrás egyik elemével, a join záradék egy üres tömböt hoz létre az elemhez. Ezért a csoportos csatlakozás alapvetően még mindig belső egyenrangú csatlakozás, azzal a különbséggel, hogy az eredményszekvencia csoportokba van rendezve.
Ha csak egy csoportillesztés eredményeit választja ki, hozzáférhet az elemekhez, de nem tudja azonosítani azokat a kulcsokat, amelyeken megegyeznek. Ezért általában hasznosabb, ha a csoportillesztés eredményeit egy olyan új típusba választja ki, amely a kulcs nevét is tartalmazza, ahogy az előző példában is látható.
A csoportillesztés eredményét természetesen használhatja egy másik alquery generátoraként is:
var innerGroupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from prod2 in prodGroup
where prod2.UnitPrice > 2.50M
select prod2;
A további információkért lásd Csoportosított illesztések végrehajtása.
Bal oldali külső illesztés
A bal oldali külső illesztésben a lekérdezés a bal oldali forrásütemezés összes elemét visszaadja, még akkor is, ha nincsenek egyező elemek a megfelelő sorrendben. Ha bal oldali külső illesztést szeretne végrehajtani a LINQ-ban, a metódus és a DefaultIfEmpty csoportillesztés együttes használatával adjon meg egy alapértelmezett jobb oldali elemet, amely akkor állítható elő, ha egy bal oldali elem nem rendelkezik egyezéssel. Alapértelmezett értékként bármilyen referenciatípushoz használhatja a null, vagy megadhat egy felhasználó által definiált alapértelmezett típust. Az alábbi példában egy felhasználó által definiált alapértelmezett típus jelenik meg:
var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product { Name = String.Empty, CategoryID = 0 })
select new { CatName = category.Name, ProdName = item.Name };
További információért lásd a következőt: „Bal oldali külső összekapcsolások végrehajtása”.
Az egyenlő operátor
A join záradék egyenlőség alapú kapcsolódást végez. Más szóval, a találatok kizárólag a két kulcs egyenlőségén alapulhatnak. Más típusú összehasonlítások, például a "nagyobb mint" vagy a "nem egyenlő" nem támogatottak. Annak érdekében, hogy az összes illesztés egyenrangú legyen, a záradék a join kulcsszót equals használja az == operátor helyett. A equals kulcsszó csak záradékban join használható, és néhány fontos módon eltér az == operátortól. A karakterláncok összehasonlításakor a equals túlterhelési lehetőséget biztosít az érték szerinti összehasonlításhoz, míg a == operátor referencia-egyenlőséget használ. Ha az összehasonlítás mindkét oldala azonos sztringváltozókkal rendelkezik, equals és == ugyanazt az eredményt éri el: igaz. Ennek az az oka, hogy amikor egy program két vagy több egyenértékű sztringváltozót deklarál, a fordító mindet ugyanazon a helyen tárolja. Ez az úgynevezett internálás. Egy másik fontos különbség a null összehasonlításnál a következő: a null equals null kiértékelése hamis equals operátorral, míg == operátorral igazként értékelődik. Végül a hatókörviselkedés eltérő: equals esetén a bal oldali kulcs a külső forrásszekvenciát, a jobb oldali kulcs pedig a belső forrást használja. A külső forrás csak a equals bal oldalán van érvényben, a belső forrásszekvencia pedig csak a jobb oldalán érvényesül.
Nem egyenrangú
A nem egyenlő illesztéseket, keresztcsatlakozásokat és más egyéni illesztési műveleteket több from záradék használatával is végrehajthatja, hogy egymástól függetlenül új sorozatokat vezessen be egy lekérdezésbe. További információért lásd a(z) Egyéni illesztési műveletek végrehajtása.
Illesztések objektumgyűjteményeken és relációs táblákon
Egy LINQ-lekérdezési kifejezésben illesztési műveleteket hajt végre objektumgyűjteményeken. Az objektumgyűjtemények nem illeszthetők össze pontosan ugyanúgy, mint két relációs tábla. A LINQ-ban csak akkor van szükség explicit join záradékokra, ha két forrásütemezés nem rendelkezik kapcsolatokkal. A LINQ és az SQL használatakor az objektummodell az idegen kulcstáblákat jelöli az elsődleges tábla tulajdonságaiként. A Northwind-adatbázisban például az Ügyfél tábla idegenkulcs-kapcsolattal rendelkezik a Rendelések táblával. Amikor a táblákat az objektummodellhez rendeli, az Ügyfél osztály rendelkezik egy Orders tulajdonsággal, amely az adott ügyfélhez társított gyűjteményt Orders tartalmazza. Valójában az illesztés már elkészült Ön számára.
További információkért a LINQ to SQL kontextusában történő kapcsolódó táblák lekérdezéséről lásd: „Adatbázis-kapcsolatok leképezésének módja”.
Összetett kulcsok
Összetett kulccsal több érték egyenlőségét is tesztelheti. További információkért lásd: Csatlakozás összetett kulcsokkal. Összetett kulcsokat is használhat egy group záradékban.
Példa
Az alábbi példa egy belső illesztés, egy csoportillesztés és egy bal oldali külső illesztés eredményeit hasonlítja össze ugyanazon az adatforráson ugyanazokkal az egyező kulcsokkal. Ezekhez a példákhoz hozzáadunk néhány további kódot, hogy egyértelműsítsük az eredményeket a konzolon.
class JoinDemonstration
{
#region Data
class Product
{
public required string Name { get; init; }
public required int CategoryID { get; init; }
}
class Category
{
public required string Name { get; init; }
public required int ID { get; init; }
}
// Specify the first data source.
List<Category> categories =
[
new Category {Name="Beverages", ID=001},
new Category {Name="Condiments", ID=002},
new Category {Name="Vegetables", ID=003},
new Category {Name="Grains", ID=004},
new Category {Name="Fruit", ID=005}
];
// Specify the second data source.
List<Product> products =
[
new Product {Name="Cola", CategoryID=001},
new Product {Name="Tea", CategoryID=001},
new Product {Name="Mustard", CategoryID=002},
new Product {Name="Pickles", CategoryID=002},
new Product {Name="Carrots", CategoryID=003},
new Product {Name="Bok Choy", CategoryID=003},
new Product {Name="Peaches", CategoryID=005},
new Product {Name="Melons", CategoryID=005},
];
#endregion
static void Main(string[] args)
{
JoinDemonstration app = new JoinDemonstration();
app.InnerJoin();
app.GroupJoin();
app.GroupInnerJoin();
app.GroupJoin3();
app.LeftOuterJoin();
app.LeftOuterJoin2();
}
void InnerJoin()
{
// Create the query that selects
// a property from each element.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { Category = category.ID, Product = prod.Name };
Console.WriteLine("InnerJoin:");
// Execute the query. Access results
// with a simple foreach statement.
foreach (var item in innerJoinQuery)
{
Console.WriteLine("{0,-10}{1}", item.Product, item.Category);
}
Console.WriteLine($"InnerJoin: {innerJoinQuery.Count()} items in 1 group.");
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin()
{
// This is a demonstration query to show the output
// of a "raw" group join. A more typical group join
// is shown in the GroupInnerJoin method.
var groupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup;
// Store the count of total items (for demonstration only).
int totalItems = 0;
Console.WriteLine("Simple GroupJoin:");
// A nested foreach statement is required to access group items.
foreach (var prodGrouping in groupJoinQuery)
{
Console.WriteLine("Group:");
foreach (var item in prodGrouping)
{
totalItems++;
Console.WriteLine(" {0,-10}{1}", item.Name, item.CategoryID);
}
}
Console.WriteLine($"Unshaped GroupJoin: {totalItems} items in {groupJoinQuery.Count()} unnamed groups");
Console.WriteLine(System.Environment.NewLine);
}
void GroupInnerJoin()
{
var groupJoinQuery2 =
from category in categories
orderby category.ID
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new
{
Category = category.Name,
Products = from prod2 in prodGroup
orderby prod2.Name
select prod2
};
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupInnerJoin:");
foreach (var productGroup in groupJoinQuery2)
{
Console.WriteLine(productGroup.Category);
foreach (var prodItem in productGroup.Products)
{
totalItems++;
Console.WriteLine(" {0,-10} {1}", prodItem.Name, prodItem.CategoryID);
}
}
Console.WriteLine($"GroupInnerJoin: {totalItems} items in {groupJoinQuery2.Count()} named groups");
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin3()
{
var groupJoinQuery3 =
from category in categories
join product in products on category.ID equals product.CategoryID into prodGroup
from prod in prodGroup
orderby prod.CategoryID
select new { Category = prod.CategoryID, ProductName = prod.Name };
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupJoin3:");
foreach (var item in groupJoinQuery3)
{
totalItems++;
Console.WriteLine($" {item.ProductName}:{item.Category}");
}
Console.WriteLine($"GroupJoin3: {totalItems} items in 1 group");
Console.WriteLine(System.Environment.NewLine);
}
void LeftOuterJoin()
{
// Create the query.
var leftOuterQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup.DefaultIfEmpty(new Product() { Name = "Nothing!", CategoryID = category.ID });
// Store the count of total items (for demonstration only).
int totalItems = 0;
Console.WriteLine("Left Outer Join:");
// A nested foreach statement is required to access group items
foreach (var prodGrouping in leftOuterQuery)
{
Console.WriteLine("Group:");
foreach (var item in prodGrouping)
{
totalItems++;
Console.WriteLine(" {0,-10}{1}", item.Name, item.CategoryID);
}
}
Console.WriteLine($"LeftOuterJoin: {totalItems} items in {leftOuterQuery.Count()} groups");
Console.WriteLine(System.Environment.NewLine);
}
void LeftOuterJoin2()
{
// Create the query.
var leftOuterQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty()
select new { Name = item == null ? "Nothing!" : item.Name, CategoryID = category.ID };
Console.WriteLine($"LeftOuterJoin2: {leftOuterQuery2.Count()} items in 1 group");
// Store the count of total items
int totalItems = 0;
Console.WriteLine("Left Outer Join 2:");
// Groups have been flattened.
foreach (var item in leftOuterQuery2)
{
totalItems++;
Console.WriteLine("{0,-10}{1}", item.Name, item.CategoryID);
}
Console.WriteLine($"LeftOuterJoin2: {totalItems} items in 1 group");
}
}
/*Output:
InnerJoin:
Cola 1
Tea 1
Mustard 2
Pickles 2
Carrots 3
Bok Choy 3
Peaches 5
Melons 5
InnerJoin: 8 items in 1 group.
Unshaped GroupJoin:
Group:
Cola 1
Tea 1
Group:
Mustard 2
Pickles 2
Group:
Carrots 3
Bok Choy 3
Group:
Group:
Peaches 5
Melons 5
Unshaped GroupJoin: 8 items in 5 unnamed groups
GroupInnerJoin:
Beverages
Cola 1
Tea 1
Condiments
Mustard 2
Pickles 2
Vegetables
Bok Choy 3
Carrots 3
Grains
Fruit
Melons 5
Peaches 5
GroupInnerJoin: 8 items in 5 named groups
GroupJoin3:
Cola:1
Tea:1
Mustard:2
Pickles:2
Carrots:3
Bok Choy:3
Peaches:5
Melons:5
GroupJoin3: 8 items in 1 group
Left Outer Join:
Group:
Cola 1
Tea 1
Group:
Mustard 2
Pickles 2
Group:
Carrots 3
Bok Choy 3
Group:
Nothing! 4
Group:
Peaches 5
Melons 5
LeftOuterJoin: 9 items in 5 groups
LeftOuterJoin2: 9 items in 1 group
Left Outer Join 2:
Cola 1
Tea 1
Mustard 2
Pickles 2
Carrots 3
Bok Choy 3
Nothing! 4
Peaches 5
Melons 5
LeftOuterJoin2: 9 items in 1 group
Press any key to exit.
*/
Megjegyzések
Egy join záradék, amelyet nem követ a intoJoin metódushívás. Egy join záradék, amelyet a into metódushívás követ GroupJoin .
Lásd még
- Lekérdezési kulcsszavak (LINQ)
- Language Integrated Query (LINQ)
- Illesztési műveletek
- csoport záradéka
- Bal oldali külső összekapcsolások végrehajtása
- Belső összekapcsolások végrehajtása
- Csoportosított illesztések végrehajtása
- Az összekapcsolási záradék eredményeinek rendezése
- Csaklakozzon összetett kulcsok használatával
- Visual Studio-val kompatibilis adatbázisrendszerek