Join mellan olika databaser i LINQ to SQL
På MSDN Live i torsdags fick jag en fråga om joins mellan olika databaser med LINQ to SQL samt hur olika 'Collations' inverkade på detta. I efterhand har jag förstått att jag nog missförstod frågan en smula - så jag tänkte försöka reda ut begreppen.
Till att börja med - vad är problemet med olika 'Collations''?
SQL Server har en inställning kallad 'Collation' som styr sorteringsordningen av textbaserad data när det gäller bokstäver med accenter, stora och små bokstäver samt specialtecken som å,ä och ö. En Collation sätts på servernivå, men du kan också sätta Collations på enskilda databaser och till och med ner på enskilda fält i databasen.
En av de vanligaste Collations som används i Sverige är Finnish_Swedish_CI_AS - där CI_AS står för Case insensitive och AS står för Accent sensitive.
Ponera att jag skulle ha två olika databaser med två olika collations där jag vill koppla ihop data mellan två tabeller. Den ena databasen har Collation Finnish_Swedish_CI_AS och den andra har Finnish_Swedish_CI_AI. I mitt testexempel innehåller bägge databaserna en tabell som heter Customer, menID-begreppet skiljer sig åt mellan de olika tabellerna, därför vill jag göra en join på Name-fältet:
En join mellan tabellerna på fältet Name skulle kunna göras såhär med TSQL:
select c1.Name, c2.Type
from JoinTestDB1.dbo.Customer c1
join JoinTestDB2.dbo.Customer c2
on c1.Name = c2.Name
Vilket skulle resultera i följande felmeddelande:
Cannot resolve the collation conflict between "Finnish_Swedish_CI_AI" and "Finnish_Swedish_CI_AS" in the equal to operation.
Sättet att lösa detta på i TSQL är genom att explicit ange Collation på det fält som ska vara nyckel i din Join:
on c1.Name COLLATE Finnish_Swedish_CI_AI = c2.Name
Men skulle jag kunna göra motsvarande Join med hjälp av LINQ to SQL istället?
Du kan inte använda en och samma DataContext mot två olika databaser - men det du kan göra är att läsa upp data från antingen bara den ena eller från bägge tabellerna och köra din Join mot objekts-kollektioner i minnet istället.
I nedan exempel hämtar jag den ena kollektionen genom att anropa .ToList() Jag kan sedan kan göra en Join mot Data Context nr 2 utan problem:
JoinTestDB1DataContext dc = new JoinTestDB1DataContext();
JoinTestDB2DataContext dc2 = new JoinTestDB2DataContext();
var cust1 = from c in dc.Customers
select c;
var joinedCust = from c in cust1.ToList()
join c2 in dc2.CustomerDB2s
on c.Name equals c2.Name
select new { c.Name, c2.Type };
Du måste naturligtvis vara medveten om att det kan innebär en märkbar påverkan på prestanda att läsa upp alla rader från databasen, hur stor den är beror på hur många rader du har i din tabell och om du har något ytterligare filter-utryck m.m. Alternativet är då att via LINQ to SQL anropa en lagrad procedur som gör samma Join istället.
Comments
Anonymous
September 30, 2008
PingBack from http://www.easycoded.com/join-mellan-olika-databaser-i-linq-to-sql/Anonymous
September 30, 2008
Det hade varit intressant med ett prestandatest där du jämför dels det du har nu, och ett där du har en stored procedure som anropas med Linq. Det skulle dessutom sitta fint med ett test där du fyller en custom collection genom en datareader som får data från SP:n. Något du orkar kolla? :)