join záradék (C# referencia)
A join
záradék olyan különböző forrásütemezésekből származó elemek társítására használható, amelyek nem rendelkeznek közvetlen kapcsolatokkal az objektummodellben. Az egyetlen követelmény az, hogy az egyes forráselemeknek legyen egy olyan értéke, amely ö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. Egy join
záradékot használhat például a termék szállítóinak és vevőinek listájának létrehozására, akik mind ugyanabban a meghatározott régióban találhatók.
A join
záradék bemenetként két forrásütemezést használ. Az egyes sorozatok elemeinek vagy olyan tulajdonságot kell tartalmazniuk, amely összehasonlítható a másik sorozat megfelelő tulajdonságával. A join
záradék a speciális equals
kulcsszó használatával hasonlítja össze az egyenlőséghez megadott kulcsokat. A záradék által join
végrehajtott összes illesztés egyenértékű. A záradék kimenetének join
alakja a végrehajtott illesztés típusától függ. A következő három leggyakoribb illesztéstípus:
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ó: Belső illesztések végrehajtása.
Csoporthoz való csatlakozás
Egy join
kifejezéssel into
rendelkező záradékot csoportillesztésnek nevezünk.
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 felel meg a bal oldali forrás egyik elemének, a join
záradék egy üres tömböt hoz létre az adott elemhez. Ezért a csoportillesztés alapvetően még mindig belső egyenrangú, azzal a kivételével, hogy az eredményütemezés 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 szintén tartalmazza a kulcsnevet, 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;
További információ: Csoportosított illesztések végrehajtása.
Bal oldali külső illesztés
Bal oldali külső illesztés esetén a rendszer a bal oldali forrásütemezés összes elemét visszaadja, még akkor is, ha a megfelelő elemek nem szerepelnek 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. Bármilyen referenciatípus alapértelmezett értékeként használható 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ó: Bal oldali külső illesztések végrehajtása.
Az egyenlő operátor
A join
záradék ekvivalens műveletet hajt végre. Más szóval csak a két kulcs egyenlőségére alapozhatja a találatokat. 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 sztringek equals
összehasonlítása során túlterhelt az érték, és az operátor ==
hivatkozási 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. Ezt internálásnak nevezzük. Egy másik fontos különbség a null összehasonlítás: null equals null
a függvény az operátorral equals
hamisként értékeli ki a függvényt, és nem ==
igazként értékeli ki. Végül a hatókörkezelési viselkedés eltérő: a equals
bal oldali kulcs a külső forrásütemezést használja, a jobb oldali kulcs pedig a belső forrást. A külső forrás csak a bal oldalon equals
található hatókörben van, a belső forrásütemezés pedig csak a jobb oldalon található hatókörben.
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ó: 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 az illesztési műveletek objektumgyűjteményeken lesznek végrehajtva. Az objektumgyűjtemények nem "csatlakoztathatók" 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ést nem köt semmilyen kapcsolat. A LINQ és az SQL használatakor az idegen kulcstáblák az objektummodellben az elsődleges tábla tulajdonságaiként jelennek meg. 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, a Customer osztály egy Rendelések tulajdonsággal rendelkezik, amely az adott ügyfélhez társított rendelések gyűjteményét tartalmazza. Az illesztés gyakorlatilag már megtörtént.
A LINQ és az SQL kontextusában lévő kapcsolódó táblák lekérdezéséről további információt az Adatbázis-kapcsolatok leképezése című témakörben talál.
Összetett kulcsok
Összetett kulccsal több érték egyenlőségét is tesztelheti. További információ: Csatlakozás összetett kulcsokkal. Az összetett kulcsok záradékokban group
is használhatók.
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: {0} items in 1 group.", innerJoinQuery.Count());
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: {0} items in {1} unnamed groups", totalItems, groupJoinQuery.Count());
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: {0} items in {1} named groups", totalItems, groupJoinQuery2.Count());
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(" {0}:{1}", item.ProductName, item.Category);
}
Console.WriteLine("GroupJoin3: {0} items in 1 group", totalItems);
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: {0} items in {1} groups", totalItems, leftOuterQuery.Count());
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: {0} items in 1 group", leftOuterQuery2.Count());
// 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: {0} items in 1 group", totalItems);
}
}
/*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
A join
nem követett into
záradék metódushívássá Join lesz lefordítva. A join
következő into
záradékot a metódushívásra GroupJoin fordítjuk le.
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ő illesztések végrehajtása
- Belső illesztések végrehajtása
- Csoportosított illesztések végrehajtása
- Illesztési záradék eredményeinek sorrendje
- Csatlakozás összetett kulcsokkal
- Kompatibilis adatbázisrendszerek a Visual Studióhoz
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: