Czy płynne interfejsy są bardziej elastyczne niż atrybuty i dlaczego?

15

W samouczku dotyczącym kodu EF 4.1 podano następujący kod:

public class Department
{
    public int DepartmentId { get; set; }
    [Required]
    public string Name { get; set; }
    public virtual ICollection<Collaborator> Collaborators { get; set; }
}

Następnie wyjaśniono, że płynny interfejs jest bardziej elastyczny:

Adnotacje danych są zdecydowanie łatwe w użyciu, ale lepiej jest zastosować podejście programowe, które zapewnia znacznie większą elastyczność.

Podano przykład użycia płynnego interfejsu:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Department>().Property(dp => dp.Name).IsRequired();
    modelBuilder.Entity<Manager>().HasKey(ma => ma.ManagerCode);
    modelBuilder.Entity<Manager>().Property(ma => ma.Name)
        .IsConcurrencyToken(true)
        .IsVariableLength()
        .HasMaxLength(20);
}

Nie rozumiem, dlaczego płynny interfejs jest podobno lepszy. Czy to naprawdę Z mojego punktu widzenia wygląda na to, że adnotacje danych są bardziej wyraźne i mają bardziej czysty semantyczny charakter.

Moje pytanie brzmi: dlaczego płynny interfejs byłby lepszym rozwiązaniem niż używanie atrybutów, szczególnie w tym przypadku?

(Uwaga: Jestem całkiem nowy w całej koncepcji płynnych interfejsów, więc proszę nie oczekiwać wcześniejszej wiedzy na ten temat.)

Odniesienie: http://codefirst.codeplex.com/

Tjaart
źródło
To pytanie tak naprawdę nie dotyczy płynnych interfejsów. Różnica polega na użyciu atrybutów i normalnego kodu. Gdyby kod nie był płynny, nie zmieniłby wiele w twoim pytaniu.
sick
Płynne interfejsy @svick są w zasadzie normalnym kodem, ale wyraża to w inny sposób. Odeszliśmy od określania rzeczy w zwykłym kodzie do atrybutów, teraz dzięki płynnym interfejsom wygląda na to, że niektórzy cofają się i idą w kierunku ponownego określania rzeczy w kodzie. Chcę tylko zrozumieć, dlaczego miałbyś używać kodu zamiast atrybutów. Czy płynne interfejsy gwarantują odejście od atrybutów i powrót do prostego kodowania wszystkiego ponownie?
Tjaart

Odpowiedzi:

13

Adnotacje danych są statyczne, na przykład ta deklaracja metody nie może się zmienić w czasie wykonywania:

  [MinLength(5)]
  [MaxLength(20,ErrorMessage="Le nom ne peut pas avoir plus de 20 caractères")]
  public new string Name { get; set; }

Płynny interfejs może być dynamiczny:

   if (longNamesEnabled)
   {
      modelBuilder.Entity<Manager>().Property(ma => ma.Name)
        .HasMaxLength(100);
   }
   else
   {
      modelBuilder.Entity<Manager>().Property(ma => ma.Name)
        .HasMaxLength(20);
   }

nie wspominając o tym, że kod może być ponownie użyty między właściwościami.

Garrett Hall
źródło
2
dlaczego miałbyś sądzić, że długość (lub jakakolwiek inna właściwość) tej samej właściwości zmieniłaby się w czasie wykonywania?
Yusubov
1
@ElYusubov: Zacznę od scenariuszy, w których nie znałem długości pola w czasie kodowania.
Wyatt Barnett
@WyattBarnett: sens może mieć długość pola jako zmienną tylko wtedy, gdy parametry domeny są pobierane dynamicznie z jakiejś usługi lub zewnętrznego nietypowego źródła. Jednak dynamiczne radzenie sobie z właściwościami domen wymagałoby defensywnego kodowania.
Juzubow
1
@ElYusubov możesz mieć dwie właściwości, które muszą być dokładnie takie same, z wyjątkiem długości, więc przekazuję je do funkcji, która ustawia je dynamicznie. Dlatego autor nazwał je bardziej elastycznymi.
Garrett Hall,
1
@ElYusubov, możesz ustawić długość pola jako ustawienie w ustawieniach projektu, które będzie przesyłane do app.config lub web.config. Następnie, jeśli zmieniła się długość pola bazy danych, możesz zmienić długość w pliku .config bez ponownej kompilacji i ponownego wdrożenia aplikacji.
Kyralessa,
8

Nie sądzę, aby to stwierdzenie powinno być szeroko stosowane; jest to bardzo specyficzne dla Code First. W Code First adnotacje danych zawierają tylko podzbiór funkcji dostępnych w płynnym interfejsie API. Innymi słowy, istnieją pewne konfiguracje modeli, które można wykonać tylko przy użyciu płynnego interfejsu API.

Oto na przykład niektóre rzeczy, których nie można określić za pomocą adnotacji:

  • Precyzja właściwości DateTime
  • Precyzja i skala właściwości numerycznych
  • Ciąg lub właściwość binarna jako stała długość
  • Właściwość String jako non-Unicode
  • Zachowanie relacji podczas usuwania
  • Zaawansowane strategie mapowania

Osobiście staram się używać adnotacji związanych z walidacją, gdy tylko jest to możliwe, ponieważ inne technologie, takie jak MVC, również mogą z nich korzystać. Do wszystkiego innego wolę płynne API.

bricelam
źródło
Czy możesz podać przykład, co można zrobić tylko za pomocą płynnego interfejsu API? Interesujące byłoby również wiedzieć, dlaczego zdecydowali się to zrobić w ten sposób. Próbuję zrozumieć interfejsy API flunt w porównaniu z bardziej konwencjonalnymi metodami, a struktura encji jest tylko przykładem. Chcę wiedzieć, dlaczego wolą to od atrybutów. Dla mnie atrybuty wydają się bardziej poprawne i czytelne.
Tjaart,
1
@ Tjaart Dodałem kilka przykładów. Projektując to, istniały dwie główne zasady motywujące. Po pierwsze, pozwól deweloperom wybrać. Niektórzy ludzie postrzegają atrybuty jako naruszenie POCO, inni lubią ich deklaratywny charakter. Po drugie, wykorzystaj istniejące atrybuty i wprowadź tylko nowe dla typowych scenariuszy. Prawdopodobnie zgodzisz się, że przykłady, które podałem powyżej, są stosunkowo rzadkie.
bricelam
Zauważyłem, że zachowanie OnDelete wydaje się być dostępne tylko w płynnym API. Czy możesz pomyśleć, dlaczego zdecydowali się to zrobić w ten sposób? Właśnie tak staram się dojść do tego pytania. Naruszenie POCO może być dobrym powodem, jeśli dzielisz klasy między projektami. Możesz skończyć z zależnością frameworku encji, której nie chcesz, jeśli użyjesz atrybutów!
Tjaart,
@ Tjaart, nie pamiętam dokładnych powodów. Dołączyłem do zespołu pod koniec funkcji Code First i nie byłem tu ze względu na jej wygląd. Zobaczę jednak, czy uda mi się ważyć kogoś innego z zespołu.
bricelam
1

Odpowiedź na twoje pytanie znajduje się w linku.

Następnie programowo definiujesz ograniczenia obowiązujące w Twojej domenie.

Zasadniczo preferuje się stosowanie Atrybutów zamiast podejścia programowego, przy czym podejście programowe ma większą kontrolę nad jednostką. Istnieje jednak niestandardowy sposób dodawania atrybutów w celu udekorowania modelu, który również możesz wyglądać.

Korzystając z tego podejścia, możesz nawet opisać relacje między tabelami i kolumnami. Podsumowując, jeśli chcesz mieć większą kontrolę nad swoją domeną, możesz zastosować to nowe podejście, które jest dostarczane z EF4.1.

Jednak w typowych scenariuszach sprawdzania poprawności zastosowanie atrybutów powinno działać dobrze, ponieważ jest odporne na większość przypadków; a ponadto może zaoszczędzić czas.

Jusubow
źródło
Czy możesz zilustrować, w jaki sposób sposób programowy daje ci większą kontrolę? Tak naprawdę nie rozumiem tego w tym momencie.
Tjaart
Weźmy na przykład ten „.IsConcurrencyToken (true)” - jak byś to zrobił w definicji atrybutu?
Yusubov
[ConcurrencyCheck] <- co w rzeczywistości wydaje się prostsze
Tjaart
dobry chwyt, jak byś opisał „relacje między tabelami i kolumnami”?
Jusubow
[ForeignKey („PersonId”)] <- podobnie, co prawdopodobnie nie jest tak proste, jak .HasForeignKey (t => t.ProjectId), chociaż wszystko, czego potrzeba, to pozwolić ForeignKey () pobrać lambda tak jak płynny interfejs. Nadal nie wyjaśnia, dlaczego jedno jest lepsze od drugiego.
Tjaart
0

Myślę, że zalecają płynny interfejs API dla pierwszych implementacji kodu, ponieważ wyraźnie opisujesz sposób tworzenia relacji w bazie danych. Jeśli używasz adnotacji danych, baza danych utworzona przez Entity Framework może nie być tym, czego oczekujesz. Twój początkowy przykład jest bardzo prosty, więc podobnie jak ty, użyłbym tylko metody adnotacji danych.

str8killinit
źródło
Czy możesz podać przykład, że baza danych nie jest tym, czego oczekujesz, i jak płynny interfejs zapobiega temu?
Tjaart,