Pytanie ASP.NET MVC i LINQ Ogólne pytania


Zadałem już kilka pytań na ten temat. Zanim będziemy w stanie wdrożyć MVC lub LINQ w pracy, musimy rozwiązać kilka problemów.

Wiele zestawów rekordów w ASP.NET MVC

Jedynymi przykładami użycia MVC są tylko jeden zestaw wyników. Podczas korzystania z procedur przechowywanych można pobrać wiele zestawów rekordów, a cały powód, dla którego stosujemy procedury składowane, jest z dwóch powodów (na pewno wielu z was jest tego świadomych). Po pierwsze na wypadek, gdybyśmy musieli przekazać parametry, a po drugie, jeśli chcemy zwrócić wiele tabel danych. W jaki sposób jest to możliwe w architekturze MVC ASP.NET?

W w tym samouczku widzimy, jak odzyskiwane są dane. Ale używa ViewData.Model co oznacza pojedynczy zestaw wyników, nie wyjaśnia, co się stanie, jeśli zwróconych zostanie wiele zestawów wyników lub jak je uzyskać.

Silnie wpisane dane wyjściowe zapisane w pamięci

Dodatkowo, przykłady na stronie ASP.NET, dotyczące używania LINQ do silnie typowej rozdzielczości danych wyjściowych, są uzyskiwane przy użyciu formatu * .dbml, który jest lustrzanym odbiciem schematu tabeli, umożliwiając wyszukiwanie pól za pomocą LINQ. Wspaniały. Ale co się stanie, jeśli dane wyjściowe są niestandardowe z procedury składowanej, która nie jest mapowana bezpośrednio do widoku lub tabeli? Jak możemy rozwiązać nazwy kolumn z tych procedur przechowywanych?

W poprzedniej sekcji opisałem w tym samouczku, ale to tylko pokazuje, jak utworzyć LINQ do SQL tylko dla tabel, a nie niestandardowe wyjście z sproc.

Wyszukiwanie kolumn LINQ

W pracy uruchamiamy makro, które eksportuje grupę klas do naszego katalogu App_Code, dzięki czemu zapisane parametry procedur są wstępnie zdefiniowane. Dzieje się tak, więc nie musimy wywoływać DeriveParameters, które składa się z dodatkowego wywołania do bazy danych. Nie chcemy, aby tak się stało, ponieważ jest duży ruch. Jeśli używamy LINQ, jak rozwiązywane są typy danych kolumn? Czy istnieje wywołanie do bazy danych za każdym razem, gdy definiujemy parametr, aby znaleźć typ danych i nazwę parametru? Czy zmieniło się coś od tego czasu? Czy wciąż wywołuje DeriveParameters za każdym razem? Czy są one gdzieś zbuforowane?

Formaty DBML

Czy pliki * .dbml powinny zawierać wszystkie tabele z bazy danych? Mamy około 15 baz danych z wieloma, wieloma tabelami w każdym.

Widok dla każdego wyjścia

Jeszcze jeden punkt do dodania do tego postu. Zamiast ręcznie tworzyć klasy dbml lepiej jest reprezentować dane jako widok, nawet jeśli jest to niestandardowe wyjście? A może lepiej utworzyć niestandardową klasę w pliku dbml?

To musi być ostatni problem, albo będę jadł moje własne ramię

"Nie można rzucić obiektu typu" SingleResult`1 [IntranetMVC.UserDetail] ", aby wpisać" IntranetMVC.UserDetail "."

Oto funkcja:

  Function Index() As ActionResult
    ViewData("Message") = "Welcome to ASP.NET MVC!"

    Dim userDetail As UserDetail
    Dim office As IList(Of Office)
    Dim activeUser As IList(Of ActiveUser)
    Dim dept As IList(Of Department)

    Using db As PersonnelDataContext = New PersonnelDataContext
      Dim results As IMultipleResults = db.UserDetail(1168)

      userDetail = results.GetResult(Of UserDetail)()
      office = results.GetResult(Of Office)()
      activeUser = results.GetResult(Of ActiveUser)()
      dept = results.GetResult(Of Department)()
    End Using

    Return View(New IndexViewData(userDetail, office, activeUser, dept))
  End Function

Występuje na wszystkich userDetail, office, activeUser i dept zadania, ale nie mam pojęcia, dlaczego. Teraz jeszcze ich nie zmapowałem poprawnie, ale weźmy na przykład Wydział pierwszy. Przeciągnąłem i upuściłem schemat tabeli na plik dbml, więc zdecydowanie istnieje i jest w odpowiednim formacie.

AKTUALIZACJA

Oto mój rzeczywisty kod. To nie jest ostateczne, bawiłem się z tym. Wygląda na to, że typy zwrotu są nieprawidłowe, ale nie jestem pewien dlaczego. Wydaje się, że tylko jeden wynik jest zwracany, gdy procedura składowana faktycznie zwraca cztery zestawy danych. Jeden z tych zestawów ma tylko jeden wynik, a pozostałe zawsze zwracają wiele wierszy:

Nie można rzucić obiektu typu "SingleResult1[IntranetMVC.Office]' to type 'System.Collections.Generic.IList1

Imports System.Data.Linq
Imports System.Reflection
Imports System.Data.Linq.Mapping

Partial Class PersonnelDataContext

  <FunctionAttribute(Name:="dbo.UserDetailProc"), _
  ResultType(GetType(UserDetail)), _
  ResultType(GetType(IList(Of Office))), _
  ResultType(GetType(IList(Of ActiveUser))), _
  ResultType(GetType(IList(Of Department)))> _
  Public Function UserDetail( _
                  <Parameter(Name:="User_Key", DbType:="Int")> ByVal User_Key As Integer, _
                  <Parameter(Name:="EditYN", DbType:="Char")> Optional ByVal EditYN As Char = "N") As IMultipleResults

    Dim result As IExecuteResult = Me.ExecuteMethodCall(Me, CType(MethodInfo.GetCurrentMethod(), MethodInfo), User_Key, EditYN)
    Return CType(result.ReturnValue, IMultipleResults)
  End Function
End Class

NAPRAWIĆ

Okay, nie zdawałem sobie sprawy, ponieważ szczerze mówiąc, nie sprawdzałem poprawnie typów zwrotu. ja przypuszczalny to result.GetResult (Of MyType) (od IMultipleResults) zwróci kolekcję. Wręcz przeciwnie, zwraca tylko pojedyncze wyniki i przenosi wskaźnik do następnego elementu w kolekcji. Niestety GetResult jest jedyną odsłoniętą metodą zwracania wyników, więc musisz powtórzyć kolekcję i dodać ją do ogólnej listy.

Dziękuję bardzo!


14
2018-04-22 10:06


pochodzenie




Odpowiedzi:


Wiele zestawów rekordów w ASP.NET MVC

Tak - zdecydowanie.

Najpierw musisz ręcznie utworzyć metodę, która wywołuje przechowywany proc, zwracając IMultipleResults wynik.

Ten post na blogu ma wszystkie potrzebne informacje. Jest prosty w obsłudze i bardzo łatwy w obsłudze.

To, co musisz zrobić, to dwa kroki.

  1. Utwórz metodę, która wywoła procedurę przechowywaną i zwróci wiele rekordów (patrz opis na blogu powyżej).
  2. Utwórz prosty obiekt klasy, który jest używany w widoku, a kontroler ustawia właściwości.

na przykład.

IndexViewData.cs
public class IndexViewData
{
    IList<Customers> Customers { get; set; }
    IList<Products> Products { get; set; }
}

.

HomeController.cs
public ActionResult Index()
{
    IList<Customers> customers;
    IList<Products> products;

    // This grabs the multiple records from a single stored procedure. 
    // This code taken from the blog post link, above.
    using (NorthwindDataContext db = new NorthwindDatacontext)
    {
        IMultipleResults results = db.GetMultipleRecordSets(arg1, ....);
        customers = results.GetResult<Customer>();
        products = results.GetProducts<Product>();
    }

    // Now return the view, with the viewdata that is required.
    return View(new IndexViewData
                    {
                        Customers = customers,
                        Products = products
                    });
}

.

Index.aspx
<%@ Page 
    Language="C#" 
    MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewPage<IndexViewData>" %>

<% Html.RenderPartial("CustomersUserControl", 
                       ViewData.Model.Customers); %>

 <br/>

<h2>Products</h2>
<% foreach(var product in ViewData.Model.Products) { %>
Name: <%= product.Name %><br/>
<% } %>

...

Proszę zauważyć, że nie zrobiłem żadnego sprawdzania błędów, itp. To naprawdę szybki przewodnik po pseduo, aby zacząć.

Uwaga # 2: Zwróć uwagę, że widok indeksu jest silnie wpisany (dziedziczy stronę ViewPage.

Silnie wpisane dane wyjściowe zapisane w pamięci

Odpowiedziałem na to powyżej. Pamiętaj, że możesz zdecydowanie wpisać swoje ISingleResult procedury przechowywane.

Wyszukiwanie kolumn LINQ

Ok, myślę, że rozumiem, co masz na myśli, tutaj. Podczas tworzenia metody, która wywołuje procedurę przechowywaną (albo ISingleResult lub IMultipleResult) definiujesz parametry, które są wymagane, tam i wtedy ... pomyśl o tym, że są zakodowane.

Gdy przeciągasz i upuszczasz tabele na płótno GUI z linq do sql, program Visual Studio wykonuje sprawdzanie tam i wtedy. Następnie tworzy klasy w jednym z różnych plików dla kontekstu. na przykład. NorthwindDataContext.designer, itp. Więc to jest jedno uderzenie. Po utworzeniu klasy projektant wyświetla ją na kanwie. Jest NO SYNC wraca do bazy danych. Żaden. Nada. Zilch. Jeśli zmienisz cokolwiek w swoim schemacie bazy danych (np. Dodaj nowe pole, zmień argument procedury składowanej, itp.) Datakekst będzie NIE o tym wiedz. Musisz usunąć tabelę i przeciągnąć ją i upuścić ponownie.

Premia premiowa!

Jeśli masz uruchomiony program SQL Profiler podczas przeciągania i upuszczania tabeli lub procedury składowanej na obszar roboczy, możesz sprawdzić, czy program Visual Studio "wysyła zapytanie" do bazy danych dla informacji. :)

Więc tak. To ogień-zapomnij. Jedno uderzenie. Wymagana synchronizacja ręczna.

HTH.

Aktualizacja

Zauważyłem, że dodałeś jeszcze dwa q, więc dodam tu moje odpowiedzi.

Formaty DBML

To jest osobista decyzja. 15 DB! shees! to uczciwa liczba. W każdym razie sprowadza się to do tego, jak można utrzymać płótno kontekstowe. Po drugie, każdy kontekst tworzy jego własne połączenie z bazą danych. Więc jeśli twoja metoda zdecyduje się wywołać 4 konteksty, to masz 4 połączenia (i wycieczki w obie strony) do bazy, koleś :)

Widok dla każdego wyjścia

Osobiście mam wszystkie moje tabele na płótnie kontekstowym. Nigdy nie używam tych klas tabeli w moim kodzie. Są one prywatne i używane tylko w mojej przestrzeni nazw repozytorium / projektu / dll. WTEDY używam POCO klasy, aby przenieść wszystkie moje rzeczy. Dzięki temu mój kod jest czystszy i nie zależy od repozytorium.

Zaktualizuj # 2

To musi być ostatni problem, albo będę jadł moje własne ramię

Jeśli przeciągnąłeś przechowywany proc na płótno kontekstu linq, usuń go. Nie ma żadnych odniesień do metody UserDetails(int userId).

Teraz dodaj następujący kod (musisz przekonwertować go na VB.NET) do częściowej klasy kontekstu danych (zakładam, że wiesz co to znaczy / znaczy btw): -

[Function("UserDetails")] // <-- This is the name of your stored procedure.
[ResultType(TypeOf(UserDetail))]
[ResultType(TypeOf(Office))]
[ResultType(TypeOf(ActiveUser))]
[ResultType(TypeOf(Department))]
public IMultipleResults UserDetails(
    [Parameter(Name = "UserId", DbType = "Int")] int userId)
//                      /\____     /\_____         ____/\                    
// This is where u _define_ the stored proc arguments.
{
    IExecuteResult result = this.ExecuteMethodCall(this, 
           ((MethodInfo)MethodInfo.GetCurrentMethod())), userId);
// This is where all the stored proc arguments are set ____/\
// This can be multiple args. eg. userId, name, ...
    return (IMultipleResults)result.ReturnValue;
}

następnie użyj go tak jak w poprzednim kodzie VB.NET.

Problem (domyślam się) polegał na tym, że nie opracowałeś metody, którą będziesz obsługiwać IMultipleResults. Nadal używasz starego, przechowywanego podpisu kodu proc, który został (domyślnie) wykonany jako pojedynczy wynik zestawu rekordów (np. ISingleResult).

Jest to ustawienie domyślne, jeśli u przeciągnij i upuść zapisaną z Server Explorer na płótnie Context Linq.


21
2018-04-22 09:57



Ah, stary - mam wrażenie. Zaktualizowałem ostatni akapit. Przeczytaj to ponownie i powiedz mi, czy mam rację (to znaczy moje zrozumienie twojego pytania, część 3). - Pure.Krome
Dodano więcej odpowiedzi, ponieważ dodałeś jeszcze 2 q. - Pure.Krome
1) Conext canvas, na co patrzysz podczas przeglądania pliku dbml. Prawidłowo 2) Ustawiam klasy XXXX_ViewData obok siebie do reprezentowanych widoków. Jeśli więc jest to widok indeksu dla kontrolera domowego, wówczas umieszczę IndexViewData w folderze View \ Home. Inni peepy umieszczają go w folderze Models i nadają mu unikalną nazwę. - Pure.Krome
Klienci to własność -> tak. - Pure.Krome
spróbuj utworzyć nowy wpis SO z kodem c # i poproś, aby ktoś zrobił to jako VB. Eekk .. vb. biedactwo. - Pure.Krome


Wiele zestawów rekordów w ASP.NET MVC:

Jeśli masz zapisaną procedurę zwracającą A i B. Następnie utworzysz określony ViewModel:

public class AB
{
  public A DataA { get; set; };
  public B DataB { get; set; };
}

Możesz także użyć słownika ViewData zamiast właściwości Model (lub w połączeniu z tą właściwością, która również działa)

Silnie wpisane dane wyjściowe zapisane w pamięci

Tworzysz określoną klasę dla wyników zwracanych z procedury składowanej z polami niestandardowymi.

Wyszukiwanie kolumn LINQ

Nie jest to w 100% pewne, ale LINQ wyszukuje nazwy pól kolumn i nazwy parametrów z procedury przechowywanej w czasie projektowania.


3



Doskonały. Tak więc w pierwszym punkcie nie jestem do końca pewien. Czy mógłbyś omówić to z małym przykładem? Drugi punkt: jak stworzyć tę klasę? Tylko w folderze modeli? Jak powinien wyglądać? Trzecia kwestia: czy wyszukiwania są wykonywane za każdym razem, gdy są dostępne, czy tylko raz? - Kezzer
Heh Michael. Podczas gdy pisałem swoją odpowiedź, zobaczyłem, że opublikowaliście swoją (ale nie przeczytaliście jej, dopóki nie napisałem). Podążamy za tym samym formatowaniem i podobnymi odpowiedziami :) wyjdź mi z głowy! :) :) - Pure.Krome
Cześć Kezzer, jak mogłeś zobaczyć Pure.Krome odpowiedział na to lepiej ode mnie. Ale wciąż mogę odpowiedzieć, jeśli chcesz. :-) - Michael