NHibernate vs LINQ to SQL

117

Jako ktoś, kto nie korzystał z żadnej technologii w rzeczywistych projektach, zastanawiam się, czy ktoś wie, w jaki sposób te dwie się uzupełniają i jak bardzo ich funkcje się pokrywają?

Manu
źródło

Odpowiedzi:

113

LINQ to SQL wymusza użycie wzorca table-per-class. Zaletą korzystania z tego wzorca jest to, że jest szybki i łatwy w implementacji, a uruchomienie domeny w oparciu o istniejącą strukturę bazy danych zajmuje bardzo niewiele wysiłku. W przypadku prostych aplikacji jest to całkowicie akceptowalne (a często nawet preferowane), ale w przypadku bardziej złożonych aplikacji programiści często sugerują użycie zamiast tego wzorca projektowania opartego na domenie (co ułatwia NHibernate).

Problem z wzorcem tabeli dla klasy polega na tym, że struktura bazy danych ma bezpośredni wpływ na projekt domeny. Załóżmy na przykład, że masz tabelę Klienci z następującymi kolumnami zawierającymi podstawowe informacje o adresie klienta:

  • Adres ulicy
  • Miasto
  • Stan
  • Zamek błyskawiczny

Załóżmy teraz, że chcesz również dodać kolumny dla adresu pocztowego klienta, więc dodasz następujące kolumny do tabeli Klienci:

  • MailingStreetAddress
  • MailingCity
  • MailingState
  • MailingZip

Korzystając z LINQ to SQL, obiekt Customer w Twojej domenie miałby teraz właściwości dla każdej z tych ośmiu kolumn. Ale gdybyś postępował zgodnie ze wzorcem projektowym opartym na domenie, prawdopodobnie utworzyłbyś klasę Adres i miałbyś klasę klienta mieć dwie właściwości Adres, jedną dla adresu pocztowego, a drugą dla ich aktualnego adresu.

To prosty przykład, ale pokazuje, w jaki sposób wzorzec tabeli na klasę może prowadzić do cuchnącej domeny. Ostatecznie to zależy od Ciebie. Ponownie, w przypadku prostych aplikacji, które potrzebują tylko podstawowych funkcji CRUD (tworzenie, odczytywanie, aktualizowanie, usuwanie), LINQ to SQL jest idealne ze względu na prostotę. Ale osobiście lubię używać NHibernate, ponieważ ułatwia to czystszą domenę.

Edycja: @lomaxx - Tak, przykład, którego użyłem, był uproszczony i mógł zostać zoptymalizowany do dobrej współpracy z LINQ to SQL. Chciałem, aby było to możliwie podstawowe, aby doprowadzić do sedna sprawy. Chodzi jednak o to, że istnieje kilka scenariuszy, w których posiadanie struktury bazy danych określającej strukturę domeny byłoby złym pomysłem lub przynajmniej prowadziłoby do nieoptymalnego projektu OO.

Kevin Pang
źródło
4
Możesz zakodować implementację swojego repozytorium za pomocą Linq To SQL, jest to bardzo przydatne.
Nicolas Dorier
1
Myślę, że to nie jest ActiveRecord, nawet zmapowane klasy zawierają część logiki infrastruktury. Wzorzec ActiveRecord byłby taki, gdybyś mógł mieć Customer.Save (). L2S implementuje wzorzec Unit of Work z klasą DataContext, podobnie jak Session w nHibernate, ale NH ma prawdziwe podejście POCO.
Hrvoje Hudo
1
@kevin "LINQ to SQL używa wzorca aktywnego rekordu" To nie jest poprawne. To tak, jakby powiedzieć, że ADO.NET używa rekordu aktywnego, a NHibernate używa rekordu aktywnego. Wszystkie są technologiami dostępu do danych i nie wymuszają żadnego konkretnego wzorca dostępu do danych. Osobiście lubię używać linq-to-sql z wzorcem repozytorium. Masz rację, że linq-to-sql nie obsługuje złożonych mapowań, takich jak NHibernate.
liammclennan
1
A co z normalizacją bazy danych i pozwoleniem na generowanie DAL przez narzędzia, np. SQLMetal?
Alex
3
@CoffeeAddict Gdy niedopasowanie impedancji jest zbyt duże do zniesienia, wtedy Twoja aplikacja jest zbyt skomplikowana, aby używać LINQ to SQL w, imo. Powodem, dla którego mój przykład jest śmierdzący, jest to, że użycie LINQ to SQL spowodowałoby 8 właściwości w przeciwieństwie do 2 i ograniczyłoby twoją zdolność do robienia rzeczy, takich jak implementowanie funkcji, które przyjmują klasę Address lub implementują procedury w klasie Address, które możesz wykonać zrobić, jeśli używałeś NHibernate.
Kevin Pang,
26

Dwie kwestie, które do tej pory zostały pominięte:

  • LINQ to SQL nie działa z Oracle ani żadną bazą danych poza SqlServer. Jednak 3rd strony oferują lepsze wsparcie dla Oracle, np dotConnect Devart jest , DbLinq , Mindscape za Lightspeed i ALinq . (Nie mam z nimi żadnych osobistych doświadczeń)

  • Linq do NHibernate pozwala używać Linq z Nhiberate, więc może usunąć powód, dla którego nie należy używać.

Wydaje się, że nowy, płynny interfejs Nhibernate sprawia, że ​​konfigurowanie mapowania Nhibernate jest mniej bolesne. (Usunięcie jednego z punktów bólu Nhibernate)


Aktualizacja

Linq do Nhiberate jest lepszy w Nhiberate v3, który jest teraz w wersji alfa . Wygląda na to, że Nhiberate v3 może zostać dostarczony pod koniec tego roku.

Podmiot Rama Praca jako .NET 4 jest także zaczynają wyglądać jak prawdziwy opcji.

Ian Ringrose
źródło
2
Linq do NHibernate jest wciąż na bardzo wczesnym etapie. Nie jest to pełne wdrożenie i prawdopodobnie nie jest w ogóle gotowe do użytku produkcyjnego.
liammclennan
Nowa wersja LinqConnect 2.0 wprowadza kilka dodatkowych funkcji zapewniających wygodę, takich jak obsługa dziedziczenia według typu, obsługa PLINQ i funkcja Batch Updates. Projektant ORM (Devart Entity Developer) ma teraz obsługę Model First i funkcję synchronizacji mapowania. Więcej szczegółów: devart.com/news/2010/dotconnects600.html
Devart
23

@Kevin: Myślę, że problem z przykładem, który prezentujesz, polega na tym, że używasz kiepskiego projektu bazy danych. Pomyślałbym, że utworzysz tabelę klientów i tabelę adresów i znormalizujesz tabele. Jeśli to zrobisz, zdecydowanie możesz użyć Linq To SQL w scenariuszu, który sugerujesz. Scott Guthrie ma świetną serię postów na temat używania Linq To SQL, które zdecydowanie polecam.

Nie sądzę, aby można było powiedzieć, że Linq i NHibernate uzupełniają się nawzajem, ponieważ sugerowałoby to, że mogą być używane razem, i chociaż jest to możliwe, o wiele lepiej jest wybrać jeden i trzymać się go.

NHibernate umożliwia bardzo elastyczne mapowanie tabel bazy danych do obiektów domeny. Umożliwia także użycie HBL do przeszukiwania bazy danych.

Linq to SQL umożliwia również mapowanie obiektów domeny do bazy danych, jednak używa składni zapytania Linq do wysyłania zapytań do bazy danych

Główna różnica polega na tym, że składnia zapytania Linq jest sprawdzana w czasie kompilacji przez kompilator, aby upewnić się, że zapytania są prawidłowe.

Należy pamiętać o tym, że linq jest dostępny tylko w .net 3.xi jest obsługiwany tylko w VS2008. NHibernate jest dostępny w wersjach 2.0 i 3.x oraz VS2005.

W przypadku NHibernate należy pamiętać o tym, że nie generuje on obiektów domeny ani plików mapowania. Musisz to zrobić ręcznie. Linq może
to zrobić automatycznie.

lomaxx
źródło
15
Co zrobić, jeśli piszesz kod w oparciu o starszą strukturę bazy danych, której nie możesz zmienić, ponieważ obsługuje ona inne aplikacje. Czy chcesz, aby model domeny dziedziczył kiepski projekt bazy danych, czy chcesz utworzyć bogaty model domeny, który może się różnić niezależnie od struktury bazy danych?
Larry Foulkrod
7

Fluent NHibernate może generować pliki mapowań w oparciu o proste konwencje. Bez pisania w XML i silnie wpisane.

Niedawno pracowałem nad projektem, w którym ze względów wydajnościowych musieliśmy zmienić Linq na SQL na NHibernate. Zwłaszcza sposób materializacji obiektów w L2S wydaje się wolniejszy niż w przypadku NHibernate, a zarządzanie zmianami jest również dość powolne. Wyłączenie zarządzania zmianami może być trudne w określonych scenariuszach, w których nie jest to potrzebne.

Jeśli zamierzasz używać jednostek odłączonych od DataContext - na przykład w scenariuszach WCF - możesz mieć wiele problemów z ponownym połączeniem ich z DataContext w celu zaktualizowania zmian. Nie miałem z tym żadnych problemów z NHibernate.

To, czego będzie mi brakowało w L2S, to głównie generowanie kodu, który utrzymuje aktualne relacje na obu końcach jednostek. Ale wydaje mi się, że istnieje kilka narzędzi dla NHibernate, które również to robią ...

asgerhallas
źródło
2
Tylko w przypadku innych przeczytać post i myślisz o skokach statku też - .ObjectTrackingEnabled = falsena swój DataContextbyłby rozwiązany problem zmiany śledzenia. Tak długo, jak kupujesz wzorzec jednostki pracy i nie chcesz robić DDD, Linq-to-SQL naprawdę zapewnia.
mattmc3
Ze względu na wydajność musieliśmy zmienić Linq na SQL na NHibernate ” - Współczuję wam, po kilku latach używania [Fluent, nie mniej] NHibernate. Myślę, że głównie oszukiwaliśmy i skończyło się na pisaniu natywnego SQL dla rzeczywistych punktów nacisku na wydajność. Byłoby interesujące usłyszeć aktualizację (sześć lat później ...) na temat przebiegu Twojej migracji i czy byłaby tego warta.
ruffin
5

Czy możesz wyjaśnić, co rozumiesz przez „LINQ”?

LINQ nie jest technologią dostępu do danych, to tylko funkcja języka, która obsługuje zapytania jako konstrukcję natywną. Może odpytać dowolny model obiektowy, który obsługuje określone interfejsy (np. IQueryable).

Wiele osób odnosi się do LINQ To SQL jako LINQ, ale to wcale nie jest poprawne. Firma Microsoft właśnie wydała LINQ To Entities z .NET 3.5 SP1. Ponadto NHibernate ma interfejs LINQ, więc możesz użyć LINQ i NHibernate, aby uzyskać dostęp do swoich danych.

Jon Galloway
źródło
2

Zakładam, że przez LINQ masz na myśli LINQ to SQL, ponieważ LINQ sam w sobie nie ma skojarzonych z nim „operacji” w bazie danych. To tylko język zapytań, który ma mnóstwo cukru składniowego, aby wyglądał jak SQL.

W bardzo podstawowych z podstawowych przykładów wydaje się, że NHibernate i LINQ to SQL rozwiązują ten sam problem. Kiedy już przejdziesz, szybko zdasz sobie sprawę, że NHibernate obsługuje wiele funkcji, które pozwalają na tworzenie naprawdę bogatych modeli domen. Istnieje również projekt LINQ to NHibernate, który umożliwia używanie LINQ do wykonywania zapytań NHibernate w taki sam sposób, jak w przypadku korzystania z LINQ to SQL.

Ryan Rinaldi
źródło
1

Najpierw oddzielmy dwie różne rzeczy: modelowanie baz danych dotyczy danych, podczas gdy modelowanie obiektowe dotyczy jednostek i relacji.

Zaletą Linq-to-SQL jest szybkie generowanie klas ze schematu bazy danych, dzięki czemu można ich używać jako obiektów rekordów aktywnych (patrz definicja wzorca projektowania rekordów aktywnych).

Zaletą NHibernate jest zapewnienie elastyczności między modelowaniem obiektów a modelowaniem w bazie danych. Bazę danych można modelować tak, aby jak najlepiej odzwierciedlała dane, biorąc pod uwagę na przykład wydajność. Podczas gdy modelowanie obiektów najlepiej odzwierciedla elementy reguły biznesowej przy użyciu podejścia, takiego jak projektowanie oparte na domenie. (patrz komentarz Kevina Panga)

W przypadku starszych baz danych ze słabymi konwencjami modelowania i / lub nazewnictwa, Linq-to-SQL odzwierciedli te niechciane struktury i nazwy w Twoich klasach. Jednak NHibernate może ukryć ten bałagan dzięki mapowaniu danych.

W projektach od podstaw, w których bazy danych mają dobre nazewnictwo i małą złożoność, Linq-to-SQL może być dobrym wyborem.

Możesz jednak użyć Fluent NHibernate z automatycznym mapowaniem do tego samego celu z mapowaniem jako konwencją. W tym przypadku nie martw się o żadne mapowanie danych z XML lub C # i pozwól NHibernate wygenerować schemat bazy danych z twoich encji w oparciu o konwencję, którą możesz dostosować.

Z drugiej strony krzywa uczenia się Linq-to-SQL jest mniejsza niż NHibernate.

Humberto
źródło
0

Lub możesz użyć projektu Castle ActiveRecords. Używam tego przez krótki czas, aby przyspieszyć nowy kod dla starszego projektu. Używa NHibernate i działa na wzorze aktywnego rekordu (zaskakujące, biorąc pod uwagę jego nazwę, którą znam). Nie próbowałem, ale zakładam, że gdy już go użyjesz, jeśli poczujesz potrzebę bezpośredniego skorzystania ze wsparcia NHibernate, nie byłoby to zbyt trudne dla części lub całego projektu.


źródło
0

Jak napisałeś „dla osoby, która nie korzystała z żadnego z nich” LINQ to SQL jest łatwy w użyciu, więc każdy może z niego łatwo korzystać. Obsługuje również procedury, które pomagają w większości przypadków. Załóżmy, że chcesz pobrać dane z więcej niż jednej tabeli, a następnie napisz procedurę i przeciągnij tę procedurę do projektanta, a utworzy ona wszystko za Ciebie. Załóżmy, że nazwa procedury to „CUSTOMER_ORDER_LINEITEM”, która pobiera rekord ze wszystkich tych trzech tabel, a następnie po prostu pisze

MyDataContext db = new MyDataContext();
List<CUSTOMER_ORDER_LINEITEMResult> records = db.CUSTOMER_ORDER_LINEITEM(pram1, param2 ...).ToList<CUSTOMER_ORDER_LINEITEMResult>();

możesz również użyć obiektu you records w pętli foreach, co nie jest obsługiwane przez NHibernate

Ali Adravi
źródło