N-warstwowa aplikacja bazodanowa bez użycia ORM, w jaki sposób interfejs użytkownika określa, czego potrzebuje do wyświetlenia danych?

Szukam wskazówek i informacji tutaj, zrobię to CW, ponieważ podejrzewam, że nie ma jednej poprawnej odpowiedzi. To jest dla C #, dlatego zrobię kilka odniesień do Linq poniżej. Przepraszam również za długi post. Pozwolę sobie podsumować pytanie tutaj, a następnie pojawia się pełne pytanie.

Podsumowanie: W 4-warstwowej aplikacji UI / BLL / DAL / DB, w jaki sposób można zmienić interfejs użytkownika, wyświetlić więcej kolumn (na przykład w siatce), uniknąć przecieku przez warstwę logiki biznesowej i do warstwy dostępu do danych, do zdobyć dane do wyświetlenia (zakładając, że jest już w bazie danych).

Załóżmy, że aplikacja warstwowa ma 3 (4) warstwy:

Interfejs użytkownika (UI)Warstwa logiki biznesowej (BLL)Warstwa dostępu do danych (DAL)Baza danych (DB; czwarta warstwa)

W tym przypadku DAL jest odpowiedzialny za konstruowanie instrukcji SQL i wykonywanie ich w bazie danych, zwracając dane.

Czy jedynym sposobem „poprawnego” skonstruowania takiej warstwy jest zawsze „wybranie *”? Dla mnie to wielki nie-nie, ale pozwól mi wyjaśnić, dlaczego się zastanawiam.

Powiedzmy, że chcę, aby mój interfejs wyświetlał wszystkich pracowników, którzy mają aktywny rekord zatrudnienia. Przez „aktywne” rozumiem, że zapisy dotyczące zatrudnienia od daty zawierają dzisiaj (a może nawet datę, którą mogę ustawić w interfejsie użytkownika).

W tym przypadku powiedzmy, że chcę wysłać wiadomość e-mail do wszystkich tych osób, więc mam pewien kod w BLL, który zapewnia, że ​​nie wysłałem już e-maila do tych samych osób itd.

W przypadku BLL wymaga to minimalnej ilości danych. Być może wywołuje warstwę dostępu do danych, aby uzyskać listę aktywnych pracowników, a następnie wywołanie, aby uzyskać listę wysłanych wiadomości e-mail. Następnie dołącza do nich i tworzy nową listę. Być może można to zrobić za pomocą warstwy dostępu do danych, nie jest to ważne.

Ważne jest to, że w warstwie biznesowej naprawdę niewiele danych jest potrzebnych. Być może potrzebuje tylko unikalnego identyfikatora dla każdego pracownika, dla obu list, aby dopasować się do niego, a następnie powiedzieć „Są to unikalne identyfikatory tych, którzy są aktywni, na które nie wysłałeś jeszcze e-maila”. Czy następnie konstruuję kod DAL, który konstruuje instrukcje SQL, które pobierają tylko to, czego potrzebuje warstwa biznesowa? To znaczy. tylko „SELECT id FROM pracownicy GDZIE ...”?

Co mam wtedy zrobić dla interfejsu użytkownika? Dla użytkownika najlepiej byłoby podać o wiele więcej informacji w zależności odczemu Chcę wysłać e-maile. Na przykład, może chciałbym podać pewne podstawowe informacje kontaktowe, lub dział, dla którego pracują, lub nazwę ich menedżera itp., Żeby nie powiedzieć, że przynajmniej podaję nazwę i adres e-mail do pokazania.

W jaki sposób interfejs użytkownika otrzymuje te dane? Czy muszę zmienić DAL, aby upewnić się, że zwrócę wystarczającą ilość danych z powrotem do interfejsu użytkownika? Czy muszę zmienić BLL, aby upewnić się, że zwraca wystarczającą ilość danych dla interfejsu użytkownika? Jeśli obiekt lub struktury danych zwrócone z DAL z powrotem do BLL mogą być również wysłane do interfejsu użytkownika, być może BLL nie wymaga znacznej zmiany, ale wtedy wymagania interfejsu użytkownika wpływają na warstwę, z którą powinien się komunikować . A jeśli dwa światy działają na różnych strukturach danych, zmiany prawdopodobnie musiałyby zostać wykonane dla obu.

A co wtedy, gdy interfejs użytkownika zostanie zmieniony, aby pomóc użytkownikowi jeszcze bardziej, dodając więcej kolumn, jak głęboko powinienem / powinienem przejść, aby zmienić interfejs użytkownika? (zakładając, że dane są już obecne w bazie danych, więc nie ma potrzeby zmiany).

Jedną z sugestii, która się pojawiła, jest użycie Linq-To-SQL i IQueryable, tak że jeśli DAL, który zajmuje się czym (jak w jakich typach danych) i dlaczego (jak w klauzulach WHERE) zwrócił IQueryables, BLL mógłby potencjalnie zwrócić je do interfejsu użytkownika, który mógłby następnie skonstruować zapytanie Linq, które pobierze potrzebne dane. Kod interfejsu użytkownika może następnie pobrać potrzebne kolumny. Działałoby to, ponieważ w przypadku IQuerables interfejs użytkownika faktycznie kończyłby zapytanie, a następnie mógłby użyć „wybierz nowy {X, Y, Z}”, aby określić, czego potrzebuje, a nawet dołączyć do innych tabel, jeśli to konieczne.

Dla mnie to wygląda na bałagan. Że interfejs użytkownika wykonuje sam kod SQL, mimo że został ukryty za nakładką Linq.

Aby jednak tak się stało, nie należy zezwalać BLL lub DAL na zamykanie połączeń z bazą danych, aw świecie typu IoC usługa DAL może zostać usunięta nieco wcześniej niż chciałby kod UI, więc Zapytanie Linq może po prostu kończyć się wyjątkiem „Nie można uzyskać dostępu do usuniętego obiektu”.

Więc szukam wskazówek. Jak daleko jesteśmy? Jak sobie z tym radzisz? Uważam, że zmiany w interfejsie użytkownika będą przeciekać przez BLL i do DAL, co jest bardzo złym rozwiązaniem, ale w tej chwili wygląda na to, że nie możemy tego zrobić lepiej.

Proszę mi powiedzieć, jak głupi jesteśmy i udowodnić, że się mylę?

I zauważ, że jest to stary system. Zmiana schematu bazy danych nie jest jeszcze w zasięgu od lat, więc rozwiązanie do używania obiektów ORM, które w zasadzie byłoby odpowiednikiem „select *”, nie jest opcją. Mamy kilka dużych tabel, których chcielibyśmy uniknąć, przeglądając całą listę warstw.

questionAnswers(2)

yourAnswerToTheQuestion