2008-11-03
HowTo: SQL Server Compact Edition mit LINQ to SQL verwenden
Bereits ein code-insideAls Antwort habe ich folgende URL geschickt:
Robert Mühsig hat sich bereits mit dieser Thematik beschäftigt. Daher habe ich die URL zu sein Blog-Eintrag als Antwort geschickt:
Kleines Problem: Geht LINQ to SQL?
Wer einmal mit LINQ to SQL gearbeitet hat, wird es sicherlich schick finden - jedenfalls schicker als das normale ADO.NET Thema. Wenn man das allerdings ausprobiert, bekommt man eine Fehlermeldung: The selected object(s) use an unsupported data provider.
http://code-inside.de/blog/2008/02/28/howto-sql-server-compact-edition-mit-linq-to-sql-verwenden/
2008-10-08
Migrating from LINQ to SQL to Entity Framework: Eager Loading
This first post in the series covers Eager Loading in LINQ to SQL, and the steps for migrating to equivalent constructs in the Entity Framework in .NET 3.5 SP1. Subsequent posts will cover Deferred Loading, LINQ specifics, concurrency, mapping, stored procedure support, and other topics. As we continue to approach the next release of the Entity Framework we will revisit how some of the new features aid in migration.
http://blogs.msdn.com/adonet/archive/2008/10/07/migrating-from-linq-to-sql-to-entity-framework-eager-loading.aspx
2008-08-31
Mit LINQ to SQL die Anzahl der Datenbankzugriffe verringern
In diesem Beitrag werden zwei LINQ-Abfragen (LINQ-Queries) vergliechen, das gleiche Resultat zurück liefern aber unterschiedlich auf die Daten zugreifen. "Viele Wege führen nach Rom."
Das folgende Beispiel basiert auf SQL Server 2005 und AdventureWorks-Datenbank (Database). Für die Daten werden die Datenbanktabellen Contact und Employee eingesetzt.
Die Datenbanktabellen Employee und Contact sind über die Felder Employee.ContactID und Contact.ContactID miteinander verknüpft. Mithilfe dieser Verknüpfung können wir von einem Employee-Record aus den Contact-Record ermitteln und diese ausgeben.
Das LINQ to SQL-Designer Tool erkennt die Verknüpfung automatisch, wenn wir die beiden Tabelle mittels Drag & Drop auf die Designer-Oberfläche ziehen. Die Verknüpfung zwischen den beiden Tabellen wird von dem LINQ to SQL-Designer Tool generierten Code (siehe AdventureWorks.designer.cs-File) wie folgt dargestellt:
[Association(Name="Contact_Employee", Storage="_Contact", ThisKey="ContactID", OtherKey="ContactID", IsForeignKey=true)]Dieser Verknüpfung ermöglicht uns auf die Contact-Daten zuzugreifen, ohne das wir innerhalb der LINQ-Abfrage (LINQ-Query) auf die Contact-Tabelle refferenzieren müssen. Der Zugriff auf die Contact-Daten erfolgt über das Objekt emp (item.emp.Contact.FirstName), den wir in unseren select definiert haben (select new {emp}).
public Contact Contact
{
get
{
return this._Contact.Entity;
}
set
{
...
}
}
using System;Als Resultat erhalten wir die folgende Liste.
using System.Linq;
namespace LinqToSqlRecursiveSample0010
{
internal class Program
{
private static void Main(string[] args)
{
var db = new AdventureWorksDataContext();
var qry = from emp in db.Employees
select new {emp};
Console.WriteLine(String.Format("{0, 10}", "EmployeeID") + "|" +
String.Format("{0, 10}", "ContactID") + "|" +
String.Format("{0, -30}", "Title") + "|" +
String.Format("{0, -15}", "FirstName") + "|" +
String.Format("{0, -10}", "MiddleName") + "|" +
String.Format("{0, -15}", "LastName"));
foreach (var item in qry)
{
Console.WriteLine(String.Format("{0, 10}", item.emp.EmployeeID) + "|" +
String.Format("{0, 10}", item.emp.ContactID) + "|" +
String.Format("{0, -30}", item.emp.Title) + "|" +
String.Format("{0, -15}", item.emp.Contact.FirstName) + "|" +
String.Format("{0, -10}", item.emp.Contact.MiddleName) + "|" +
String.Format("{0, -15}", item.emp.Contact.LastName));
}
}
}
}
Wenn wir aber im Hintergrund die Datenbankzugriffe auswerten, stellen wir fest, dass die Applikation für jeden Contact-Record auf die Datenbank zugreift und die Daten aus der Datenbank ermittelt. Die Analyse mit dem SQL Server Profiler-Tool zeigt die Zugriffe wie folgt:
SELECT [t0].[EmployeeID],
[t0].[NationalIDNumber],
[t0].[ContactID],
[t0].[LoginID],
[t0].[ManagerID],
[t0].[Title],
[t0].[BirthDate],
[t0].[MaritalStatus],
[t0].[Gender],
[t0].[HireDate],
[t0].[SalariedFlag],
[t0].[VacationHours],
[t0].[SickLeaveHours],
[t0].[CurrentFlag],
[t0].[rowguid],
[t0].[ModifiedDate]
FROM [HumanResources].[Employee] AS [t0]
Die Contact-Daten werden dann pro Employee-Record aus der Datenbank gelesen (siehe unten - @p0=1209 ist die ContactID).
exec sp_executesql N'SELECT [t0].[ContactID],
[t0].[NameStyle],
[t0].[Title],
[t0].[FirstName],
[t0].[MiddleName],
[t0].[LastName],
[t0].[Suffix],
[t0].[EmailAddress],
[t0].[EmailPromotion],
[t0].[Phone],
[t0].[PasswordHash],
[t0].[PasswordSalt],
[t0].[AdditionalContactInfo],
[t0].[rowguid],
[t0].[ModifiedDate]
FROM [Person].[Contact] AS [t0]
WHERE [t0].[ContactID] = @p0',N'@p0 int',@p0=1209
Wenn wir unseren LINQ-Query mit einem join wie folgt erweitern (join con in db.Contacts on emp.ContactID equals con.ContactID) und nicht nur die Employee-Daten sondern auch die Contact-Daten in unser select einschliessen (select new {emp, con}), werden wir feststellen, dass die Contact-Daten nicht mehr einzeln aus der Datenbank gelesen, sondern die Contact-Daten mit Employee-Daten zusammen mit einem SELECT-Statement aus der Datenbank ermittelt werden.
using System;
using System.Linq;
namespace LinqToSqlRecursiveSample0010
{
internal class Program
{
private static void Main(string[] args)
{
var db = new AdventureWorksDataContext();
var qry = from emp in db.Employees
join con in db.Contacts on emp.ContactID equals con.ContactID
select new {emp, con};
Console.WriteLine(String.Format("{0, 10}", "EmployeeID") + "|" +
String.Format("{0, 10}", "ContactID") + "|" +
String.Format("{0, -30}", "Title") + "|" +
String.Format("{0, -15}", "FirstName") + "|" +
String.Format("{0, -10}", "MiddleName") + "|" +
String.Format("{0, -15}", "LastName"));
foreach (var item in qry)
{
Console.WriteLine(String.Format("{0, 10}", item.emp.EmployeeID) + "|" +
String.Format("{0, 10}", item.emp.ContactID) + "|" +
String.Format("{0, -30}", item.emp.Title) + "|" +
String.Format("{0, -15}", item.con.FirstName) + "|" +
String.Format("{0, -10}", item.con.MiddleName) + "|" +
String.Format("{0, -15}", item.con.LastName));
}
}
}
}
Als Resultat erhalten wir weiterhin die gleichen Daten:
Und im SQL Server Profiler-Tool sehen wir, dass die Contact-Daten nicht mehr einzeln ermittelt werden:
Vom LINQ to SQL generierte SQL-Statement sieht wie folgt aus:
SELECT [t0].[EmployeeID],
[t0].[NationalIDNumber],
[t0].[ContactID],
[t0].[LoginID],
[t0].[ManagerID],
[t0].[Title],
[t0].[BirthDate],
[t0].[MaritalStatus],
[t0].[Gender],
[t0].[HireDate],
[t0].[SalariedFlag],
[t0].[VacationHours],
[t0].[SickLeaveHours],
[t0].[CurrentFlag],
[t0].[rowguid],
[t0].[ModifiedDate],
[t1].[ContactID] AS [ContactID2],
[t1].[NameStyle],
[t1].[Title] AS [Title2],
[t1].[FirstName],
[t1].[MiddleName],
[t1].[LastName],
[t1].[Suffix],
[t1].[EmailAddress],
[t1].[EmailPromotion],
[t1].[Phone],
[t1].[PasswordHash],
[t1].[PasswordSalt],
[t1].[AdditionalContactInfo],
[t1].[rowguid] AS [rowguid2],
[t1].[ModifiedDate] AS [ModifiedDate2]
FROM [HumanResources].[Employee] AS [t0]
INNER JOIN [Person].[Contact] AS [t1] ON [t0].[ContactID] = [t1].[ContactID]
Viel Spass...
2008-08-28
A number of SQL Server 2008 features are not supported by LINQ to SQL
Für mein Blog wollte ich ein Beispiel mit LINQ to SQL und Geo-Daten schreiben und dabei den SQL Server 2008 einsetzen und den neuen Datentyp "geography" verwenden.
Leider wurde meine Arbeit durch die folgende Fehlermeldung unterbrochen, nach dem ich die Address-Tabelle-Table der AdventureWorks-Datenbank-Database auf die LINQ to SQL Designer-Oberfläche gezogen habe: One or more selected items contain a data type that is not supported by the designer.
Den SP 1 - Service Pack 1 für Visual Studio 2008 habe ich bereits installiert gehabt. Nach einer kurze recherche im Internet habe ich kein Eintrag zu diesem Thema gefunden.
Nach einem Post an das LINQ to SQL-Forum hat Damien Guard (Microsoft) folgenden Antwort zurück geschrieben:
A number of SQL Server features are not supported by LINQ to SQL even with SP1 installed - this includes geography and hierarchy types.
Auf meine Frage, ob Sie die neuen Datentypen unterstützen werden, bekam ich folgende Antwort zurück:
Supporting the missing types are on our list of features we'd like to add to the next release but I can't confirm what will make it at this point in time.
Den Forum-Eintrag findet ihr unter: LINQ to SQL Designer and SQL Server 2008 "geography" Data Type
Ich werde euch am laufenden halten, sobald ich Neuigkeiten zu diesem Thema habe.
CSV-Datei mit LINQ erstellen
Im folgenden Beispiel wird gezeigt, wie wir ein CSV-File mit LINQ erstellen können. Als Datenbank wird die SQL Server 2005 AdventureWorks-Datenbank verwendet.
Die Erstellung des CSV-Files erfolgt in drei Schritten:
Schritt 1: Die Daten aus der Datenbank ermitteln.
string conStr =
@"Data Source=IBM-E6A5BAE860C\SQL2K5;Initial Catalog=AdventureWorks;Integrated Security=True";
var db = new AdventureWorksDataContext(conStr);
IQueryable<ProductCategory> qry = from pc in db.ProductCategories
select pc;
Schritt 2: Die Felder für den Export in das CSV-File bestimmen.
int[] field1 = qry.Select(f => f.ProductCategoryID).ToArray();
string[] field2 = qry.Select(f => f.Name).ToArray();
Guid[] field3 = qry.Select(f => f.rowguid).ToArray();
In diesem Schritt werden die Werte der einzelnen Felder in einem Array-Objekt gespeichert. Der Select-Operator hilft uns dabei, die Wert zu ermitteln.
Schritt 3: Die Daten in das CSV-File schreiben.
TextWriter txtWrt = new StreamWriter(@"C:\ProductCategories.csv");
for (int i = 0; i < field1.Length; i++)
{
txtWrt.Write(field1[i] + ";");
txtWrt.Write(field2[i] + ";");
txtWrt.Write(field3[i].ToString());
txtWrt.WriteLine();
}
txtWrt.Close();
Den vollständigen Code findet ihr unten:
using System;
using System.IO;
using System.Linq;
namespace LinqCsvSamples0010
{
internal class Program
{
private static void Main(string[] args)
{
string conStr =
@"Data Source=IBM-E6A5BAE860C\SQL2K5;Initial Catalog=AdventureWorks;Integrated Security=True";
var db = new AdventureWorksDataContext(conStr);
IQueryable<ProductCategory> qry = from pc in db.ProductCategories
select pc;
int[] field1 = qry.Select(f => f.ProductCategoryID).ToArray();
string[] field2 = qry.Select(f => f.Name).ToArray();
Guid[] field3 = qry.Select(f => f.rowguid).ToArray();
TextWriter txtWrt = new StreamWriter(@"C:\ProductCategories.csv");
for (int i = 0; i < field1.Length; i++)
{
txtWrt.Write(field1[i] + ";");
txtWrt.Write(field2[i] + ";");
txtWrt.Write(field3[i].ToString());
txtWrt.WriteLine();
}
txtWrt.Close();
Console.ReadLine();
}
}
}
Ein ZIP-File für den Download findet ihr unter: LinqCsvSamples0010
Unter CodeProject findet ihr zu diesem Thema folgenden Artikel: LINQ to CSV library
Viel Spass...
2008-07-18
LINQ to SQL und WinForm - DataBinding mit BindingSource (DataGridView, TextBox, formattingEnabled Parameter)
Ein Leser von meinem Buch LINQ hat mir die Frage gestellt, wie er in einer WinForm Applikation (WinForm Application) ein numerisches Feld (numeric field) in der Datenbank (database) aktualisieren kann.
Er schreibt, dass er nur die String-Felder (string fields) in der Datenbank (database) aktualisieren kann aber die Änderungen an Numeric-Felder ignoriert werden.
In dem folgenden Beispiel wird der SQL Server als Datenbank (database) und LINQ to SQL wird für den Datenzugriff verwendet. Die Daten werden in einem DataGridView-Control aufgelistet, die mit Hilfe einer BindingSource-Komponente mit den Daten verknüpft ist. Zusätzlich ermöglichen die zwei TextBox-Controls die Bearbeitung der Daten. Die beiden TextBox-Controls sind ebenfalls mit Hilfe der BindingSource-Komponente mit den Daten verknüpft.
Die Datenbanktabelle Person im Design-Modus:
Script für die Datenbanktabelle (database table) Person:
USE [SampleDb]
GO
/****** Object: Table [dbo].[Person] Script Date: 07/18/2008 21:56:34 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Person](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Age] [int] NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
WinForm im Desing-Modus sieht wie folgt aus:
Und Source-Code innerhalb unser WinForm sieht wie folgt aus:
using System;
using System.Linq;
using System.Windows.Forms;
namespace LinqToSqlDataBindingSample
{
public partial class Form1 : Form
{
private SampleDbDataContext db;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.db = new SampleDbDataContext();
this.loadData();
}
private void loadData()
{
var qry = from p in db.Persons
select p;
this.bindingSource1 = new BindingSource();
this.bindingSource1.DataSource = qry;
this.dataGridView1.DataSource = this.bindingSource1;
this.txtName.DataBindings.Add("Text", this.bindingSource1, "Name");
this.txtAge.DataBindings.Add("Text", this.bindingSource1, "Age", true);
}
private void btnOK_Click(object sender, EventArgs e)
{
MessageBox.Show(this.db.GetChangeSet().ToString());
this.db.SubmitChanges();
}
}
}
Das Age-Feld ist hier als Numeric bzw. als Int definiert. Wie in der folgende Zeilen auch ersichtlich, unterscheiden sich die DataBindings. Beim Feld Age wird noch der Parameter formattingEnabled verwendet.
this.txtName.DataBindings.Add("Text", this.bindingSource1, "Name");
this.txtAge.DataBindings.Add("Text", this.bindingSource1, "Age", true);
Wenn der Parameter formattingEnabled den Wert false besitzt oder nicht verwendet wird, dann wird die eingegebene Zahl in das TextBox-Control vom DataBinding ignoriert und der alte Wert wird wieder in das Feld zurück geschrieben.
Ein kleiner Ausschnitt aus einem MSDN-Artikel zu diesem Thema:
Automatic Formatting Using Code
In earlier versions of the .NET Framework you had to manually perform the type conversions and formatting using the Format and Parse events of the Binding object. You can now do this by enabling formatting on the Binding object, either by setting the FormattingEnabled property directly or passing true to the Add method of the ControlBindingsCollection. In addition, you will need to specify a format string, either using the Add method, or by setting the FormatString property of the Binding object.
The following code includes two formatting examples. The first formatting example shows how to create a binding between a DateTime value in the data source and the Text value of a TextBox control. The FormattingEnabled property is set on the Binding object, the FormatString value specifies that the DateTime should be formatted as a long date/time string, and the binding is added to the collection.
Behind the Scenes: Improvements to Windows Forms Data Binding in the .NET Framework 2.0, Part 1
Das Beispielprojekt findet Ihr unter: LinqToSqlDataBindingSample
Viel Spass
2008-05-11
Microsoft SQL Server 2008 CTP Unterstützung für Visual Studio 2005 und Visual Studio 2008
SQL Server 2008 CTP Unterstützung für Visual Studio 2005 kann unter folgende URL heruntergeladen werden: Visual Studio 2005 Support for SQL Server 2008 CTP
Für die Einschränkungen und bekannte Fehler (Known Issues) bitte die Informationen auf der Downlad-Seite lesen.
SQL Server 2008 CTP Unterstützung für Visual Studio 2008 kann unter folgende URL heruntergeladen werden: Visual Studio 2008 Support for SQL Server 2008 CTP
Leider Unterstützt dieser Version den LINQ to SQL Designer mit SQL Server 2008 noch nicht.
Auch bei dieser Download, für die Einschränkungen und bekannte Fehler (Known Issues) bitte die Informationen auf der Download-Seite lesen.
Für Allgemeine Informationen über die SQL Server 2008 CTP Unterstützung kann ich Euch folgende Seite empfehlen: Connecting to Microsoft SQL Server 2008 from Microsoft Visual Studio 2005 and 2008
2008-04-24
LINQ to SQL - Transaction Beispiel
Als Transaktion (von lat. trans „über“, actio zu agere „(durch)führen“) bezeichnet man in der Informatik eine feste Folge von Operationen, welche als eine logische Einheit betrachtet werden. Transaktionen werden von Transaktionssystemen verarbeitet; diese erzeugen dabei aus mehreren Transaktionen eine Historie. Meist kommen sie bei Datenbanken zum Einsatz.
Quelle: Wikipedia.de
In LINQ wird eine Transaktion automatisch gestartet, wenn die SubmitChanges-Methode der DataContext-Klasse aufgerufen wird. Dabei verwendet LINQ to SQL eine explizite Transaktion.
Eine manuelle Kontrolle über die Transaktion kann durch Erstellung ein eigenes Transaction-Objekt übernommen werden.
Für den folgenden lauffähigen Beispielcode wird die AdventureWorks-Datenbank verwendet. Eine LINQ to SQL Classes-Datei (dbml-Datei) mit dem Namen AdventureWorks.dbml und mit einer Entity-Klasse
1 using System;
2
3 namespace LinqTransactionSample0001
4 {
5 class Program
6 {
7 static void Main(string[] args)
8 {
9 // DataContext Objekt erstellen
10 AdventureWorksDataContext db = new AdventureWorksDataContext();
11
12 // Transaction Objekt erstellen und mit NULL initialisieren
13 System.Data.Common.DbTransaction trans = null;
14
15 // Datenbankverbindung öffnen und den aktiven Transaction der Verbindung
16 // an das trans Objekt übergeben
17 db.Connection.Open();
18 trans = db.Connection.BeginTransaction();
19
20 // DataContext Objekt wird ab hier das trans Objekt für die Transaktionen verwenden
21 db.Transaction = trans;
22
23 // Zwei neue CountryRegion Objekte erstellen
24 CountryRegion cr1 = new CountryRegion();
25 cr1.Name = "Country ABC";
26 cr1.CountryRegionCode = "ABC";
27 cr1.ModifiedDate = DateTime.Now;
28
29 CountryRegion cr2 = new CountryRegion();
30 cr2.Name = "Country DEF";
31 cr2.CountryRegionCode = "DEF";
32 cr2.ModifiedDate = DateTime.Now;
33
34 // CountryRegion Objekt an die CountryRegions Collection hinzufügen
35 db.CountryRegions.InsertOnSubmit(cr1);
36 db.CountryRegions.InsertOnSubmit(cr2);
37
38 try
39 {
40 db.SubmitChanges();
41
42 // Wenn bis hier keinen Fehler auftritt, wird die Commit-Method des Transaction-Objekts aufgrufen
43 // und die Daten werden in die Datenbank geschrieben.
44 // Commit transaction
45 trans.Commit();
46 }
47 catch(Exception ex)
48 {
49 // Bei einem Fehler-Fall wird die Rollback-Methode des Transaction-Objektes aufgerufen
50 // Rollback transaction
51 if ( trans != null)
52 {
53 trans.Rollback();
54 }
55
56 Console.WriteLine(ex.Message.ToString());
57 }
58 finally
59 {
60 // Die Datenbank-Verbindung schliessen, wenn die Verbidung offen ist.
61 // Close the connection
62 if(db.Connection.State == System.Data.ConnectionState.Open)
63 {
64 db.Connection.Close();
65 }
66 }
67
68 Console.ReadKey();
69 }
70 }
71 }
72
Das Beispiel-Projekt findet Ihr unter: LinqTransactionSample0001
2008-01-20
Auffüllen eines DataSets mit LINQ to SQL
LINQ to SQL ermöglicht die Ermittlung der Daten aus einem SQL Server. Mit LINQ to SQL sind keine SQL-Anweisungen im Programmcode nötig, um die Daten aus der Datenbank ermitteln zu können. Die nötigen SQL-Anweisungen werden im Hintergrund generiert und die Daten werden mithilfe dieser Anweisungen aus der Datenbank ermittelt. Die aus der Datenbank ermittelte Daten stehen als Resultat der LINQ to SQL-Abfrage für die Weiterverwendung zur Verfügung.
Das Resultat der LINQ to SQL-Abfrage kann nicht direkt in ein DataSet-Objekt weitergegeben werden. LINQ bietet keine Methode für die Weitergabe vom Resultat einer LINQ-Abfrage in ein DataSet-Objekt. Die LoadDataRow-Methode der DataTable-Klasse kann für das Transferieren einer LINQ-Abfrage Resultates in ein DataTable-Objekt verwendet werden.
In dem folgenden Beispielcode wird gezeigt, wie die LoadDataRow-Methode das Resultat einer LINQ-Abfrage in ein DataTable-Objekt weitergibt.
private void btnLoadWithLinqToSql_Click(object sender, EventArgs e)
{
AdventureWorksDataContext db = new AdventureWorksDataContext();
var qry = from cr in db.CountryRegions
select cr;
this._AdventureWorksDS = new DataSet("AdventureWorks");
DataTable countryRegionDT = new DataTable("CountryRegion");
countryRegionDT.Columns.Add("CountryRegionCode", typeof(string));
countryRegionDT.Columns.Add("Name", typeof(string));
countryRegionDT.Columns.Add("ModifiedDate", typeof(DateTime));
foreach(var cr in qry)
{
countryRegionDT.LoadDataRow(new Object[] {cr.CountryRegionCode,
cr.Name,
cr.ModifiedDate}, true);
}
this._AdventureWorksDS.Tables.Add(countryRegionDT);
this.dgvLinqToSql.DataSource = this._AdventureWorksDS.Tables["CountryRegion"];
}
Die wichtigsten Zeilen im obigen Beispielcode sind die foreach-Schleife und der Aufruf der LoadDataRow-Methode. Mit der foreach-Schleife werden die einzelnen Entity-Objekten gelesen und mithilfe der LoadDataRow-Methode werden die einzelnen Eigenschaften dieser Objekte an das DataTable-Objekt weitergegeben.
foreach(var cr in qry)
{
countryRegionDT.LoadDataRow(new Object[] {cr.CountryRegionCode,
cr.Name,
cr.ModifiedDate}, true);
}
Wenn ein typisiertes DataSet verwendet wird, steht unter der DataTable-Klasse eine Methode zum Hinzufügen eines Row-Objektes zur Verfügung. In dem Beispiel wird die AddCountryRegion-Methode aufgerufen und die einzelnen Eigenschaften des Entity-Objekts übergeben:
AdventureWorksDataContext db = new AdventureWorksDataContext();
var qry = from cr in db.CountryRegions
select cr;
AdventureWorksTypedDS ds = new AdventureWorksTypedDS();
foreach (var cr in qry)
{
ds.CountryRegion.AddCountryRegionRow(cr.CountryRegionCode,
cr.Name,
cr.ModifiedDate);
}
this.dgvLinqToSql.DataSource = ds.CountryRegion;
2007-12-03
LINQ
LINQ ist die Abkürzung für Language Integrated Query.
Im Jahr 2002 wurde das .NET Framework V1.0 und Visual Studio 2002 als Entwicklungsumgebung vorgestellt. In der Zwischenzeit hat das .NET Framework mehrere Versionen hinter sich und wir Entwickler haben mit jeder Version unsere Erfahrungen gemacht.
Die neueste .NET Framework Version 3.5 und die Entwicklungsumgebung Visual Studio 2008 ist hier und wird uns Entwickler bei der Entwicklung von neuen Softwareprodukten unterstützen.
Die Version 1.0 hat eine kurze Lebensdauer hinter sich. Fast ein Jahr später wurde bereits die Version 1.1 mit Visual Studio 2003 veröffentlicht. Die Verbesserungen und Erweiterungen zwischen den beiden Versionen waren nicht sehr groß.
Im Jahre 2005 veröffentlichte Microsoft die Version 2.0 des .NET Frameworks mit Visual Studio 2005, die bisher aktuellste Versionen waren.
Die Version 3.0 wurde im Jahr 2006 veröffentlich und beinhaltete die neue Technologie wie WCF, WPF und WF.
Mit jeder Version wurde das .NET Framework erweitert und die Erweiterungen haben uns Entwickler geholfen, effizienter zu arbeiten.
November 2007 war es soweit für die neueste Version des .NET Frameworks. Die Version 3.5 mit der Visual Studio 2008 wird vom Microsoft in englischer Version veröffentlicht.
.NET Framework 3.5 bringt auch neue Spracherweiterungen mit sich. Die Programmiersprachen C# 3.0 und Visual Basic 9.0 sind mit neuen Sprachfeatures ausgestattet. Diese Spracherweiterungen waren für eine vollständige Unterstützung von LINQ notwendig.
Eine von den wichtigsten Erneuerungen im .NET Framework 3.5 ist das LINQ.
LINQ ermöglicht die Integration von SQL ähnlichen Anweisungen (LINQ-Abfragen) direkt in den Quelltext. Diese Integration vereinfacht den Zugang zu den relationalen Daten und XML-Dokumenten. Auch die Collections können mit Hilfe von LINQ-Abfragen einfacher ausgewertet werden als bisher.
LINQ steht mit dem .NET Framework 3.5 für die .NET Programmiersprachen zur Verfügung. Die .NET Programmiersprachen mussten mit neuen Sprachfeatures erweitert werden, damit sie die LINQ-Implementierung einsetzen können. Die meist verbreiteten.NET Sprachen C# und Visual Basic wurden für die Verwendung vom LINQ mit diesen neuen Features erweitert.
In dieser Version unterstützt LINQ als Datenquelle den SQL Server, XML-Dokumente und die .NET-Objekte. Damit ein .NET-Objekt als Datenquelle verwendet werden kann, muss das Objekt das IEnumerable-Interface implementieren. Die Architektur von LINQ ist in der folgende Darstellung ersichtlich.
C# 3.0 | Visual Basic 9.0 | Andere .NET Sprachen |
.NET Language Integrated Query | ||
Datenquellen | ||
LINQ to SQL | LINQ to XML | LINQ to Objects |
Relationale Daten SQL Server | XML | Objekte |
LINQ unterstützt nicht nur den SQL Server, XML-Dateien und Objekte als Datenquelle. Mit einem spezifischen LINQ Provider kann eine beliebige Datenquelle LINQ fähig gemacht werden.
Es sind bereits mehrere Projekte vorhanden, in denen für verschiedene Datenquellen LINQ-Providers realisiert werden. Die bekannteste von diesen Projekten sind Active Directory, LDAP, SharePoint und Flickr LINQ Providers.
2007-11-25
LINQ to SQL Beta 1 and 2 to RTM Changes
Die Beispiele, welche ich mit Visual Studio 2008 Beta 2 erstellt habe, konnte ich mit der aktuelle RTM Version nicht kompilieren.
Diverse Methodennamen der Beta 2 wurden umbenannt. Die bisherige Add, AddAll und Remove, RemoveAll Methoden haben neuen Namen bekommen.
Die folgende Tabelle zeigt die alten und neuen Namen der betroffenenen Add- und Remove-Methoden. Diese Methoden betreffend LINQ to SQL - Entity Klassen.
| Beta 2 Version | RTM Version |
| Add() | InsertOnSubmit() |
| AddAll() | InsertAllOnSubmit() |
| Remove() | DeleteOnSubmit() |
| RemoveAll() | DeleteAllOnSubmit() |
Die Umbennung der Methodennamen sind vom Blickwinkel Datenbank-Entwickler sinnvoll. Wenn wir einen neuen Datensatz hinzufügen möchten, verwenden wir die INSERT-Anweisung und wenn wir etwas löschen möchten verwenden wir die DELETE-Anweisung.
Die Änderungen sind auch vom Programm Manager LINQ to SQL (Dinesh Kulkarni) so argumentiert.
2007-11-03
Query Operatoren (Query Operators) und SQL-Befehle (SQL-Commands)
---------------------------
Aggregate > (Exception)
All > WHERE
Any > WHERE IN
AsEnumerable >
AsQueryable >
Average > AVG
Cast >
Concat > UNION ALL
Contains > WHERE IN
Count > COUNT
DefaultIfEmpty >
Distinct > SELECT DISTINCT
ElementAt >
ElementAtOrDefault >
Empty >
Except > WHERE NOT IN
First >
FirstOrDefault > SELECT TOP 1 ORDER BY
GroupBy > GROUP BY
GroupJoin > LEFT OUTER JOIN
GroupJoin > RIGHT OUTER JOIN
Intersect > WHERE IN
Join > INNER JOIN
Last >
LastOrDefault > SELECT TOP 1 ORDER BY DESC
Like >
LongCount > COUNT
Max > MAX
Min > MIN
OrderBy > ORDER BY
OrderByDescending > ORDER BY DESC
Range >
Repeat >
Reverse > (Exception)
Select > SELECT
SelectMany > CROSS JOIN
SelectMany > INNER JOIN
SelectMany > LEFT OUTER JOIN
SequenceEqual >
Single >
SingleOrDefault >
Skip > NOT IN
SkipWhile > (Exception)
Sum > SUM
Take > TOP n
TakeWhile > (Exception)
ThenBy > ORDER BY
ThenByDescending > ORDER BY DESC
ToArray >
ToDictionary >
ToList >
ToLookup >
Union > UNION
Where > WHERE
2007-10-31
Query Operatoren
Restriktionsoperator
Where
Projektionsoperatoren
Select
SelectMany
Aufteilungsoperatoren
Skip
SkipWhile
Take
TakeWhile
Join-Operatoren
GroupJoin
Join
Konkatinierungsoperator
Concat
Sortieroperatoren
OrderBy (descending)
ThenBy (descending)
Reverse
Gruppierungsoperatoren
GroupBy
Set-Operatoren
Set
Distinct
Except
Intersect
Union
Konvertierungsoperatoren
AsEnumerable
AsQueryable
Cast
ToArray
ToDictionary
ToList
ToLookup
Vergleichsoperatoren
SequenceEqual
Elementoperatoren
ElementAt
ElementAtOrDefault
First
FirstOrDefault
Last
LastOrDefault
Single
SingleOrDefault
DefaultIfEmpty
Generierungsoperatoren
Empty
Range
Repeat
Quantifizierungsoperatoren
All
Any
Contains
Aggregatoperatoren
Aggregate
Average
Count
LongCount
Max
Min
Sum
Andere
Like (StartWith)
2007-10-07
Intersect
er Intersect-Operator gibt Elemente als Resultat zurück, welche in den beiden Quellen vorkommen. Die zweite Quelle wird als Parameter des Intersect-Operatos mitgegeben.
Lambda Expression
Wir ermitteln zuerst alle SalesTerritories-Daten mit der CountryRegionCode US und den Resultat speichern wir in die territoriesUs-Variable.
var territoriesUs = _db.SalesTerritories
.Where(tus => tus.CountryRegionCode == "US")
.Select(tus => tus);
Im zweiten Schritt ermitteln wir alle SalesTerritories, die den Group-Wert North America entsprechen und speichern das Resultat in die TerritoriesNorthAmerica-Variable.
var territoriesNorthAmerica = _db.SalesTerritories
.Where(tna => tna.Group == "North America")
.Select(tna => tna);
In den dritten Schritten ermitteln wir alle salesTerritories, welche im ersten und zweiten Resultat vorkommen und speichern das Resultat in diet territories-Variable.
var territories = territoriesUs
.Intersect(territoriesNorthAmerica);
SQL-Anweisung
SELECT [t0].[TerritoryID],
[t0].[Name],
[t0].[CountryRegionCode],
[t0].[Group] AS [Group],
[t0].[SalesYTD],
[t0].[SalesLastYear],
[t0].[CostYTD],
[t0].[CostLastYear],
[t0].[rowguid],
[t0].[ModifiedDate]
FROM [Sales].[SalesTerritory] AS [t0]
WHERE [t0].[CountryRegionCode] = @p0
-- @p0: Input String (Size = 2; Prec = 0; Scale = 0) [US]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
SELECT DISTINCT [t0].[TerritoryID],
[t0].[Name],
[t0].[CountryRegionCode],
[t0].[Group] AS [Group],
[t0].[SalesYTD],
[t0].[SalesLastYear],
[t0].[CostYTD],
[t0].[CostLastYear],
[t0].[rowguid],
[t0].[ModifiedDate]
FROM [Sales].[SalesTerritory] AS [t0]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM [Sales].[SalesTerritory] AS [t1]
WHERE ([t0].[TerritoryID] = [t1].[TerritoryID])
AND ([t1].[Group] = @p0)
)) AND ([t0].[CountryRegionCode] = @p1)
-- @p0: Input String (Size = 13; Prec = 0; Scale = 0) [North America]
-- @p1: Input String (Size = 2; Prec = 0; Scale = 0) [US]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
2007-09-28
Take
Wir wählen die ersten fünf Währungseinträge aus der Liste aller 105 Währungen.
Als Resultat erwarten wir die Liste mit den ersten 5 Währungen.
Lambda Expression
var qry = _db.Currencies
.Select(cr => cr)
.Take(5);
SQL-Anweisung
Take(5) wird bei der SQL-Generierung zu TOP 5 umgewandelt.
SELECT TOP 5 [t0].[CurrencyCode],
[t0].[Name],
[t0].[ModifiedDate]
FROM [Sales].[Currency] AS [t0]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
Resultat
Die SQL-Anweisung liefert aus der Currency-Datenbanktabelle die ersten fünf Einträge.
2007-09-17
GroupBy
Query Expression-Anweisung
Die folgende Anweisung gruppiert die City-Werte und gibt als Resultat den City-Wert und Anzahl, wie viel mal der Wert im Resultat vorkommt.
var qry = from pa in _db.Addresses
group pa by pa.City into pag
orderby pag.Key
select new { City = pag.Key, CityCount = pag.Count() };
SQL-Anweisung
Die Query Expression-Anweisung wird wie folgt als SQL-Anweisung übersetzt.
SELECT [t1].[City], [t1].[value] AS [CityCount]
FROM (
SELECT COUNT(*) AS [value], [t0].[City]
FROM [Person].[Address] AS [t0]
GROUP BY [t0].[City]
) AS [t1]
ORDER BY [t1].[City]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
Resultat
Im Resultat sind die Datensätze nach City-Wert gruppiert und die Anzahl der City-Werte in der Datenbanktabelle aufgelistet.
Query Expression-Anweisung mit mehreren Feldern
Auch mehrere Felder können für die Gruppierung der Daten mit der GroupBy-Methode verwendet werden. In dem folgenden Beispiel werden die Daten nach City und ModifiedDate Werten gruppiert.
Die einzelnen Felder, welche für die Gruppierung verwendet wurden, stehen unter der Key-Eigenschaft zur Verfügung.
var qry2 = from pa in _db.Addresses
group pa by new {pa.City, pa.ModifiedDate.Year} into pag
orderby pag.Key.City, pag.Key.Year
select new {
City = pag.Key.City,
Year = pag.Key.Year,
ModificationCount = pag.Count()};
SQL-Anweisung
Die beiden Felder, welche für die Gruppierung verwendet wurden, sind in der SQL-Anweisung auch ersichtlich.
SELECT [t2].[City], [t2].[value2], [t2].[value] AS [ModificationCount]
FROM (
SELECT COUNT(*) AS [value], [t1].[City], [t1].[value] AS [value2]
FROM (
SELECT DATEPART(Year, [t0].[ModifiedDate]) AS [value], [t0].[City]
FROM [Person].[Address] AS [t0]
) AS [t1]
GROUP BY [t1].[City], [t1].[value]
) AS [t2]
ORDER BY [t2].[City], [t2].[value2]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
Resultat
Als Resultat wird die Anzahl der Mutation pro City und pro Jahr zurückgegeben. In dem Beispiel ist ersichtlich, dass Adressen mit dem City-Wert Albany im Jahr 2002 und 2003 je zwei Modifikationen hat.
2007-09-11
LINQ to SQL Beta2 to RTM Key Changes
http://forums.microsoft.com/MSDN/showpost.aspx?postid=2061468&siteid=1&¬ification_id=27123913&message_id=27123913
2007-08-30
DuplicateKeyException
Zuerst werden die vom DataContext überwachten Objekte geprüft, ob der Primärschlüssel-Wert bereits von einem Objekt in Verwendung ist. Wenn ja, dann wird die DuplicateKeyException generiert, ohne die Daten an die Datenbank weiterzugeben. Wenn der Primärschlüssel in den überwachten Objekten nicht vorkommt, dann wird die generierte SQL-Anweisung an die Datenbank weitergegeben. Ab hier ist es die Aufgabe der SQL-Server, sicherzustellen, dass der Primärschlüssel weiterhin in der Datenbanktabelle eindeutig bleibt. Daher ist es möglich, dass eine SqlException betreffend Primärschlüssel Verletzung generiert wird.
2007-08-25
ChangeConflictException
2007-08-20
Single oder SingleOrDefault Methode
Im Beispiel wird ein Datensatz mit Hilfe einer Lambda Expression über das Feld ProductCategoryID selektiert.
ProductCategory productCategory = _productCategoryTable.Single(pc => pc.ProductCategoryID == productCategoryID);
Die ProductCategoryID ist das Primärschlüsselfeld der ProductCategory Tabelle und somit kann der Datensatz über dieses Schlüssen Feld eindeutig identifiziert werden.
Die Single Methode feuert eine Exception, wenn der Datensatz in der Datenbank nicht existiert.

Sie können die SingleOrDefault Methode verwenden, wenn Sie nicht sicher sind, ob der Datensatz wirklich in der Datenbank vorhanden ist.
Die SingleOrDefault Methode liefert einen Null Wert zurück, wenn der Datensatz nicht ermittelt werden kann.
ProductCategory productCategory = _productCategoryTable.SingleOrDefault(pc => pc.ProductCategoryID == productCategoryID);
In diesem Fall können Sie das productCategory Objekt auf Null Wert prüfen, bevor Sie einen Wert aus dem Objekt lesen.