Przejdź do treści

Łączenie wielu tabel za pomocą NHibernate QueryOver

NHibernate to popularny framework ORM (Object-Relational Mapping) dla platformy .NET, który umożliwia programistom interakcję z bazami danych za pomocą obiektów .NET. Jedną z kluczowych operacji podczas pracy z bazami danych jest łączenie (ang. join) wielu tabel w celu pobrania powiązanych danych. QueryOver to oparta na Fluent API składnia zapytań w NHibernate, która zapewnia bardziej intuicyjny i bezpieczny typowo sposób konstruowania zapytań SQL. Metoda JoinAlias jest kluczowa w QueryOver do definiowania relacji między tabelami i umożliwia łączenie wielu encji na podstawie ich powiązań.

Poniżej przedstawiono przykład łączenia czterech powiązanych ze sobą encji: Person, PersonFavorites, PersonCompany i Company.

Definicje encji:

public class Person
{
    public virtual int Id { get; set; }
    public virtual ICollection<PersonFavorites> Favorites { get; set; }
    public virtual ICollection<PersonCompany> Companies { get; set; }
}

public class PersonFavorites
{
    public virtual Person Person { get; set; }
    public virtual Favorite Favorite { get; set; }
}

public class PersonCompany
{
    public virtual Person Person { get; set; }
    public virtual Company Company { get; set; }
}

public class Company
{
    public virtual int Id { get; set; }
    // Inne właściwości...
}

public class Favorite
{
    public virtual int Id { get; set; }
    // Inne właściwości...
}

Zapytanie z użyciem QueryOver:

Person personAlias = null;
PersonFavorites personFavoriteAlias = null;
PersonCompany personCompanyAlias = null;
Company companyAlias = null;

var query = session.QueryOver<Person>(() => personAlias)
    .JoinAlias(() => personAlias.Favorites, () => personFavoriteAlias)
    .JoinAlias(() => personAlias.Companies, () => personCompanyAlias)
    .JoinAlias(() => personCompanyAlias.Company, () => companyAlias)
    .Where(() => personCompanyAlias.Person.Id == 123) // Przykład warunku
    .List<Person>();

W tym przykładzie, za pomocą metody JoinAlias, łączymy encję Person z kolekcją Favorites poprzez alias personFavoriteAlias, następnie z kolekcją Companies poprzez alias personCompanyAlias, a na końcu łączymy PersonCompany z Company poprzez alias companyAlias. Klauzula Where filtruje wyniki, wybierając tylko te osoby, dla których Id w tabeli PersonCompany wynosi 123.

Dodatkowe scenariusze użycia JoinAlias:

  1. Pobieranie ulubionych produktów użytkownika wraz z informacjami o firmie, która je oferuje: Załóżmy, że mamy encje User, UserFavoriteProduct, Product i Supplier. Możemy użyć JoinAlias do pobrania wszystkich ulubionych produktów danego użytkownika wraz z nazwą dostawcy każdego produktu.

    ```csharp User userAlias = null; UserFavoriteProduct userFavoriteAlias = null; Product productAlias = null; Supplier supplierAlias = null;

    var favoriteProducts = session.QueryOver(() => userAlias) .JoinAlias(() => userAlias.FavoriteProducts, () => userFavoriteAlias) .JoinAlias(() => userFavoriteAlias.Product, () => productAlias) .JoinAlias(() => productAlias.Supplier, () => supplierAlias) .Where(() => userAlias.Id == currentUserId) .Select( Projections.Property(() => productAlias.Name), Projections.Property(() => supplierAlias.Name) ) .List(); ```

  2. Wyświetlanie wszystkich zamówień złożonych przez klientów z określonego miasta wraz z informacjami o produktach w tych zamówieniach: Mając encje Customer, Order, OrderItem i Product, możemy połączyć te tabele, aby znaleźć wszystkie zamówienia klientów z danego miasta i wyświetlić nazwy produktów w każdym zamówieniu.

    ```csharp Customer customerAlias = null; Order orderAlias = null; OrderItem orderItemAlias = null; Product productAlias = null;

    var customerOrders = session.QueryOver(() => customerAlias) .JoinAlias(() => customerAlias.Orders, () => orderAlias) .JoinAlias(() => orderAlias.OrderItems, () => orderItemAlias) .JoinAlias(() => orderItemAlias.Product, () => productAlias) .Where(() => customerAlias.City == "Warszawa") .SelectList(list => list .Select(() => customerAlias.Name).WithAlias(() => new { CustomerName = default(string) }) .Select(() => orderAlias.OrderDate).WithAlias(() => new { OrderDate = default(DateTime) }) .Select(() => productAlias.Name).WithAlias(() => new { ProductName = default(string) }) ) .List(); ```

  3. Znalezienie wszystkich pracowników należących do działów zlokalizowanych w konkretnym budynku: Przy założeniu istnienia encji Employee, Department i Building, możemy połączyć te tabele, aby znaleźć wszystkich pracowników pracujących w działach znajdujących się w określonym budynku.

    ```csharp Employee employeeAlias = null; Department departmentAlias = null; Building buildingAlias = null;

    var employeesInBuilding = session.QueryOver(() => employeeAlias) .JoinAlias(() => employeeAlias.Department, () => departmentAlias) .JoinAlias(() => departmentAlias.Building, () => buildingAlias) .Where(() => buildingAlias.Address.Contains("ul. Nowa")) .List(); ```

Metoda JoinAlias w NHibernate QueryOver jest potężnym narzędziem do efektywnego łączenia wielu powiązanych tabel i pobierania złożonych zestawów danych w sposób obiektowy i typowo bezpieczny. Umożliwia tworzenie czytelnych i łatwych w utrzymaniu zapytań, które odzwierciedlają relacje między encjami w bazie danych.