| NHibernate Tutorial (3): HQL Queries |
| Section: Database | Rating: 5 |
 | CodeGod submitted this resource The member's homepage is http://www.codegod.de Visit the profile here |
Attachment
Introduction
| Mit NHibernate hat man die Möglichkeit mit einer hausgemachten Query-Language (Hibernate Query Language) Anfragen an die Datenbank zu stellen. Der Vorteil hierbei ist, dass man vollkommen unabhängig von Datenbank-spezifischen SQL-Dialekten agieren kann. Wem das nicht reicht, der kann auch natives SQL absetzen. Dieser Artikel zeigt anhand von Beispielen, wie HQL verwendet wird. Es wird vom Beispiel es Artikels NHibernate Tutorial (2) ausgegangen, also eine Datenbank CompanyDB mit 2 Tabellen: Company und Employee. | |
Figure 1Die Skripte
Zunächst mal die Skripte zum Erstellen der Tabellen (für SQL-Server). Zu der Tabelle Employee ist noch ein Feld Income hinzugekommen, das wir für Aggregat-Funktionen verwenden werden:
USE CompanyDB
go
CREATE TABLE [dbo].[Company] (
[IdCompany] int IDENTITY(1,1) NOT NULL,
[Name] varchar(200) NOT NULL,
CONSTRAINT [PK_Company] PRIMARY KEY([IdCompany])
)
CREATE TABLE [dbo].[Employee] (
[IdEmployee] int IDENTITY(1,1) NOT NULL,
[Name] varchar(50) NOT NULL,
[Income] float NOT NULL,
[IdCompany] int NOT NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY([IdEmployee])
)
ALTER TABLE [dbo].[Employee]
ADD CONSTRAINT [FK_Employee_Company]
FOREIGN KEY([IdCompany])
REFERENCES [dbo].[Company]([IdCompany])
ON DELETE NO ACTION
ON UPDATE NO ACTION
INSERT INTO [dbo].[Company]([Name])
VALUES('Company1')
INSERT INTO [dbo].[Company]([Name])
VALUES('Company2')
INSERT INTO [dbo].[Employee]([Name], [Income], [IdCompany])
VALUES( 'Mark', 1000, 1)
INSERT INTO [dbo].[Employee]([Name], [Income], [IdCompany])
VALUES( 'Tom', 1500, 1)
INSERT INTO [dbo].[Employee]([Name], [Income],[IdCompany])
VALUES( 'Al', 2300, 2)
Der Zugriff
Im zweiten Tutorial haben wir uns für den Datenzugriff DataAccessObjects wie z.B. die Klasse CompanyDAO erstellt. Diese sind von BaseDAO abgeleitet und haben somit Zugriff auf alle notwendigen Funktionen zum abfragen und manipulieren von Daten. Um allerdings via HQL Abfragen absetzen zu können, benötigen wir eine zusätzliche Funktion in der BaseDAO-Klasse:
public IList GetByHQL(string hqlString )
{
IList items = null;
ISession session = SessionProvider.Instance.GetSession();
try
{
IQuery query = session.CreateQuery( hqlString );
items = query.List();
return items;
}
catch (Exception ex)
{
throw new DataAccessException("Error getting items by HQL", ex);
}
finally
{
SessionProvider.Instance.CloseSession();
}
}
Für unser Beispiel-Projekt, das ausschließlich der Demonstration von HQL dienen soll, leiten wir mal eine Klasse GenericDAO von der obigen abstrakten Basisklasse ab, um die HQL-Zugriffsfunktion zur Verfügung zu haben:
namespace CG.DataAccess.BO
{
public class GenericDAO : BaseDAO
{
}
}
Nun setzen wir eine WinForms-Applikation auf, welche die HQL-Queries über die Klasse GenericDAO ausführt und das Ergebnis der Queries in einer TextBox darstellt.
Die Anwendung stellt alle Queries, die wir ausführen möchten, in einer Liste bereit. Für eine HQL-Query habe ich eine Wrapper-Klasse erstellt, die neben der eigentlichen Query weitere Informationen bzgl .der Query hält:
public class QueryWrapper
{
private string _name;
private string _description;
private string _query;
public QueryWrapper(string name, string description, string query)
{
_name = name;
_description = description;
_query = query;
}
public string Name
{
get { return _name; }
}
public string Description
{
get { return _description; }
}
public string Query
{
get { return _query; }
}
}
Jetzt können wir QueryWrapper-Objekte erstellen, diese in eine Liste packen und sie an eine ListBox binden. Bei Selektion einer Query werden die Zusatzinformationen zur Query in TextBoxen angezeigt. Auf den Button Run Query hin, wird die jeweiligen Anfrage ausgeführt und das Ergebnis in einer weiteren TextBox dargestellt:
// Queries zur Liste hinzufügen
_queries = new List<QueryWrapper>();
_queries.Add( new QueryWrapper(
"All Companies",
"Get all available Companies",
"from Company" ) );
// Query ausführen und Ergebnis darstellen
private void RunQuery()
{
txtResult.Clear();
string hqlQuery = txtQueryHQL.Text;
GenericDAO genericDAO = new GenericDAO();
IList result = genericDAO.GetByHQL( hqlQuery );
foreach( object o in result )
txtResult.Text += o.ToString() + "\r\n";
}
Die Queries
Hier einige Erläuterungen zu den Beispiel-Queries der Applikation:
// Alle Companies abfragen. Select kann weggelassen werden, da wir nicht
// an speziellen Feldern interessiert sind
from Company
// Alle Companies abfragen die mit 1 enden. Dies ist ein Beispiel für
// die Verwendung einer LIKE-Suche
from Company as c where c.Name like '%1'
// Alle Employees abfragen die in Company1 arbeiten. Diese Query
// demonstriert wie man einen inner join verwendet
select e from Company as c inner join c.Employees as e where c.Name = 'Company1'
// Das gleiche wie oben, nur kürzer. Der join ergibt sich implizit durch
// die Verwendung des Company-Objektes. Man erhlält so alle Employees die
// in Company2 arbeiten.
from Employee as e where e.Company.Name = 'Company2'
// So bekommt man alle Employees raus, die für irgendeine Firma arbeiten.
// Dieses Beispiel soll lediglich die Funktion elements erläutern,
// mit der man Elemente von Collections abfragen kann.
select elements(c.Employees) from Company c
// Auch Aggregat-Funktionen sind natürlich möglich. Hier ein Beispiel wie
// die Summe der Einkommen aller Mitarbeiter berechnen kann.
select sum(e.Income) from Employee e
// Diese Query gibt alle Employees zurück, deren Namen in einer Menge von
// Namen liegen.
from Employee e where e.Name in ('Test', 'Another', 'Mark')
// Und so kann man alle Companies abfragen, die Mitarbeiter haben.
// (Nicht besonders sinnvoll, zeigt aber die Funktionen
// exists und elements).
from Company c where exists elements(c.Employees)
Das Beispiel-Projekt eignet sich übrigens gut zum Testen von eigenen Queries. Viel Spaß wünsche ich!