Общие вопросы ASP.NET MVC и LINQ

Я задал несколько вопросов по этой теме раньше. Прежде чем мы сможем реализовать MVC или LINQ на работе, нам нужно решить несколько проблем.

Несколько наборов записей в ASP.NET MVC

Единственные примеры использования MVC имеют только один возвращаемый набор результатов. При использовании хранимых процедур можно получить несколько наборов записей, и вся причина, по которой мы склонны использовать хранимые процедуры, состоит из двух причин (что, я уверен, многие из вас также знают). Во-первых, если нам нужно передать параметры, а во-вторых, если мы хотим вернуть несколько таблиц данных. Как это возможно в архитектуре ASP.NET MVC?

В этот учебник мы видим, как извлекаются данные. Но он использует ViewData.Model, который указывает единый набор результатов, он не объясняет, что произойдет, если возвращаются несколько результирующих наборов или как их получить.

Сильно напечатанный файл хранимой процедуры

Кроме того, примеры на веб-сайте ASP.NET для использования LINQ для строго типизированного разрешения вывода достигаются с помощью формата *.dbml, который является зеркальным отображением схемы таблицы, позволяющей искать в полях с использованием LINQ. Отлично. Но что произойдет, если ваш выход является настраиваемым из хранимой процедуры, которая не сопоставляется непосредственно ни с представлением, ни с таблицей? Как мы разрешаем имена столбцов из этих хранимых процедур?

В предыдущем разделе я описал этот учебник, но это также показывает только, как создавать LINQ to SQL только для таблиц, а не для пользовательского вывода от sproc.

Поиск столбцов LINQ

На работе мы запускаем макрос, который экспортирует кучу классов в нашу папку App_Code, поэтому параметры хранимой процедуры предварительно определены. Это сделано, поэтому нам не нужно вызывать DeriveParameters, который состоит из дополнительного вызова базы данных. Мы не хотим, чтобы это произошло, потому что там много трафика. Если мы используем LINQ, как разрешаются типы данных столбцов? Есть ли запрос к базе данных каждый раз, когда мы определяем параметр, чтобы узнать тип данных и имя параметра? С чего изменилось? Он все еще вызывает DeriveParameters каждый раз? Эти кешированные где-то?

Форматы DBML

Должны ли файлы *.dbml включать все таблицы из базы данных? У нас есть около 15 баз данных с большим количеством таблиц в каждом.

Просмотр для каждого выхода

Еще один момент, чтобы добавить к этому сообщению. Вместо того, чтобы вручную создавать классы dbml, лучше ли представлять данные в виде представления, даже если это пользовательский вывод? Или лучше создать пользовательский класс в файле dbml?

Это должно быть последней проблемой, или я буду использовать свою собственную руку

"Невозможно применить объект типа 'SingleResult`1 [IntranetMVC.UserDetail]' для ввода 'IntranetMVC.UserDetail'.

Здесь функция:

  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

Он встречается во всех назначениях userDetail, office, activeUser и dept, но я понятия не имею, почему. Теперь я пока неправильно их не наметил, но возьму, например, Департамент. Я перетащил схему таблиц в файл dbml, поэтому она определенно существует и находится в правильном формате.

UPDATE

Вот мой реальный код. Это не окончательно, я играл с ним. Кажется, что типы возврата неверны, но я не уверен, почему. Кажется, что только один результат возвращается, когда хранимая процедура фактически возвращает четыре набора данных. Один из этих наборов имеет только один результат, остальные всегда имеют несколько возвращенных строк:

Невозможно передать объект типа "SingleResult 1[IntranetMVC.Office]' to type 'System.Collections.Generic.IList 1

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

FIX

Хорошо, я не понимал, потому что, честно говоря, я не правильно проверял возвращаемые типы. Я предположил, что results.GetResult(Of MyType) (из IMultipleResults) вернет коллекцию. Наоборот, он возвращает только одиночные результаты и перемещает указатель на следующий элемент в коллекции. К сожалению, GetResult - единственный открытый метод для возврата результатов, поэтому вам нужно перебирать коллекцию и добавлять их в общий список.

Большое спасибо!

Ответы

Ответ 1

Несколько наборов записей в ASP.NET MVC

Yep - наиболее определенно.

Сначала вам нужно вручную создать метод, который вызывает хранимый процесс, возвращая результат IMultipleResults.

В этих сообщениях в блоге есть все необходимое вам. Это просто сделать и очень легко и работает.

Что вам нужно сделать, это два шага.

  • Создайте метод, который вызывает хранимую процедуру и возвращает несколько записей (см. выше в блоге).
  • Создайте простой объект класса, который используется в представлении, и контроллер устанавливает свойства.

например.

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/>
<% } %>

...

Обратите внимание, что я не проверил проверку ошибок и т.д. это действительно быстрый справочник кода pseduo для запуска u.

Примечание # 2: Обратите внимание, что представление индекса строго типизировано (оно наследует ViewPage.

Сильно напечатанный файл хранимой процедуры

Я ответил на это выше. Обратите внимание: u может сильно набирать ваши хранимые процедуры ISingleResult.

Поиск столбцов LINQ

Хорошо, я понимаю, что понимаю, что вы имеете в виду. Когда вы создаете свой метод, который вызывает хранимую процедуру (либо ISingleResult, либо IMultipleResult), вы определяете требуемые параметры, то и тут... думайте об этом как о жестко закодированном.

Когда вы перетаскиваете таблицы с перетаскиванием в linq в sql-контекст gui canvas, Visual Studio делает проверку проверки там и потом. Затем он создает классы в одном из различных файлов для контекста. например. NorthwindDataContext.designer и т.д. Итак, это однократная работа. После создания класса дизайнер затем отображает это на холсте. Существует NO SYNC обратно в базу данных. Никто. Нада. Шиш. Если вы измените что-либо в своей схеме базы данных (например, добавьте новое поле, измените аргумент хранимой процедуры и т.д.), Datacontext НЕ узнает об этом. Вам нужно удалить таблицу и перетащить ее обратно.

Бонусный трюк!

Если у вас есть SQL Profiler, работающий во время перетаскивания таблицы или хранимой процедуры на холст, вы можете увидеть, как Visual Studio "запрашивает" базу данных для информации.:)

Так что да. Это огонь-н-забыть. Однократная работа. Требуемая ручная синхронизация.

НТН.

Update

Я заметил, что вы добавили еще два q, поэтому я добавлю ответы ниже.

Форматы DBML

Это личное решение. 15 DB! shees! это справедливое число. В любом случае, это сводится к тому, насколько легко поддерживается ваш холст Context. Во-вторых, каждый контекст создает его СОБСТВЕННОЕ соединение с базой данных. Поэтому, если ваш метод решает назвать 4 контекста, у вас есть 4 соединения (и круглые поездки) в db, чувак:)

Вид для каждого выхода

Лично у меня есть все мои таблицы на холсте контекста. Я никогда не использую эти классы таблиц в своем коде. Они являются частными и используются только в моем пространстве имен/проекте/dll хранилища. я THEN используйте классы POCO, чтобы переместить все мои вещи. Это сохраняет мой код, чище и не зависит от репозитория.

Обновление # 2

Это должна быть последняя проблема или я буду есть свой собственный рука

Если вы перетащили сохраненный proc на холст контекста linq, удалите его. Не нужно ссылаться на метод UserDetails(int userId).

Теперь добавьте следующий код (вам нужно будет преобразовать его в VB.NET) в частичный класс контекста данных (я предполагаю, что вы знаете, что это означает/означает, 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;
}

то используйте его, как и в предыдущем коде VB.NET.

Проблема (я предполагаю) заключалась в том, что вы не использовали метод для обработки IMultipleResults. Вы по-прежнему используете старую хранимую кодовую подпись proc, которая была сделана (по умолчанию) только для одного результата набора записей (т.е. ISingleResult).

Это значение по умолчанию, если u перетащить-n-drop из сохраненного из Server Explorer в Linq Context Canvas.

Ответ 2

Несколько наборов записей в ASP.NET MVC:

Если у вас есть хранимая процедура, возвращающая A и B. Затем вы создаете конкретную ViewModel:

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

Вы также можете использовать словарь ViewData вместо свойства Model (или в сочетании с этим свойством, которое также работает)

Сильно напечатанный файл хранимой процедуры

Вы создаете определенный класс для результатов, возвращаемых из хранимой процедуры, с настраиваемыми полями.

Поиск столбцов LINQ

Не уверен на 100%, но LINQ ищет имена полей столбцов и имена параметров из хранимой процедуры во время разработки.