ASP.NET MVC и LINQ Общие вопросы - PullRequest
14 голосов
/ 22 апреля 2009

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

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

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

В этом уроке мы видим, как извлекаются данные. Но он использует 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 является единственным доступным методом возврата результатов, поэтому вам нужно выполнить итерацию по коллекции и добавить их в общий список.

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

Ответы [ 2 ]

21 голосов
/ 22 апреля 2009

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

Да - определенно.

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

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

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

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

например.

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

...

Обратите внимание, что я не проверял ошибки и т. Д. Это очень быстрое руководство по псевдо-коду для начала работы.

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

Вывод хранимой процедуры строго типизированного типа

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

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

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

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

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

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

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

НТН.

Обновление

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

Форматы DBML

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

Представление для каждого выхода

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

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

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

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

Теперь добавьте следующий код (вам необходимо преобразовать его в VB.NET) в частичный класс контекста данных (я предполагаю, что вы знаете, что это значит / означает, кстати):

[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).

Это значение по умолчанию, если вы перетаскиваете данные, сохраненные из обозревателя серверов, в контекстную среду linq.

3 голосов
/ 22 апреля 2009

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

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

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

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

Вывод хранимой процедуры строго типизированного типа

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...