Linq to SQL хранимые процедуры с несколькими результатами

Мы выполнили следующий подход, чтобы получить данные из нескольких результатов, используя LINQ To SQL

CREATE PROCEDURE dbo.GetPostByID
(
    @PostID int
)
AS
    SELECT    *
    FROM      Posts AS p
    WHERE     p.PostID = @PostID

    SELECT    c.*
    FROM      Categories AS c
    JOIN      PostCategories AS pc
    ON        (pc.CategoryID = c.CategoryID)
    WHERE     pc.PostID = @PostID

Вызывающий метод в классе, наследуемый от DataContext, должен выглядеть так:

[Database(Name = "Blog")]
public class BlogContext : DataContext
{
    ... 

    [Function(Name = "dbo.GetPostByID")]
    [ResultType(typeof(Post))]
    [ResultType(typeof(Category))]
    public IMultipleResults GetPostByID(int postID)
    {
        IExecuteResult result = 
            this.ExecuteMethodCall(this, 
                  ((MethodInfo)(MethodInfo.GetCurrentMethod())), 
                  postID);

        return (IMultipleResults)(result.ReturnValue);
    }
}

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

public interface IMultipleResults : IFunctionResult, IDisposable
{
    IEnumerable<TElement> GetResult<TElement>();
}

чтобы программа могла использовать этот интерфейс для получения результатов:

BlogContext ctx = new BlogContext(...);

IMultipleResults results = ctx.GetPostByID(...);

IEnumerable<Post> posts = results.GetResult<Post>();

IEnumerable<Category> categories = results.GetResult<Category>();

В приведенных выше хранимых процедурах у нас было два запроса 1. Выберите запрос без присоединения 2. Выберите запрос с подключением

Но в приведенном выше втором запросе выбора данные, которые отображаются, относятся к одной из таблицы, то есть из таблицы категорий. Но мы использовали соединение и хотим отобразить таблицу данных с результатами из обеих таблиц, то есть из категорий, а также из PostCategories.

  • Пожалуйста, если кто-нибудь может сообщить мне, как это сделать, используя LINQ to SQL
  • Что такое компромисс производительности, если мы используем вышеуказанный подход в отношении реализации вышеуказанного подхода с помощью простого SQL

Ответы

Ответ 1

Скотт Гатри (парень, который управляет командами .Net dev в MS) рассказал, как сделать это в своем блоге несколько месяцев назад намного лучше чем когда-либо, ссылка здесь. На этой странице есть раздел под названием "Обработка нескольких форм результата из SPROC". Это объясняет, как обрабатывать несколько результатов из хранимых procs разных форм (или одинаковой формы).

Я очень рекомендую подписаться на его RSS-канал. Он в значительной степени авторитетный источник во всех вещах .Net.

Ответ 2

Хейя чувак - это работает?

IEnumerable<Post> posts;
IEnumerable<Category> categories;

using (BlogContext ctx = new BlogContext(...))
{
    ctx.DeferredLoadingEnabled = false; // THIS IS IMPORTANT.
    IMultipleResults results = ctx.GetPostByID(...);
    posts = results.GetResult<Post>().ToList();
    categories = results.GetResult<Category>().ToList();
}
// Now we need to associate each category to the post.
// ASSUMPTION: Each post has only one category (1-1 mapping).
if (posts != null)
{
    foreach(var post in posts)
    {
        int postId = post.PostId;
        post.Category = categories
            .Where(p => p.PostId == postId)
            .SingleOrDefault();
    }
}

Ok. давайте сломаем это.

Сначала вверх, приятное соединение внутри используемого блока (так что он удаляется красиво).

Затем убедитесь, что DEFERRED LOADING выключен. В противном случае, когда u попытается выполнить и выполнить набор (например, post.Category == blah), он увидит, что он равен нулю, lazy-load данные (например, сделать rountrip базы данных) установить данные, а THEN переопределить то, что было просто перетащено из db, с результатом метода Where(..). уф! Резюме: убедитесь, что отложенная загрузка отключена для области запроса.

Наконец, для каждого сообщения повторяйте и установите категорию из второго списка.

Помогает ли это?

ИЗМЕНИТЬ

Исправлено так, чтобы он не выдавал ошибку перечисления, вызывая методы ToList().

Ответ 3

Просто любопытно, если Post имеет один или несколько категорий, возможно ли вместо использования цикла for загружать Post.PostCategories со списком категорий (один для многих), всего одним выстрелом, используя ПРИСОЕДИНЯЙТЕСЬ?

var rslt = from p in results.GetResult<Post>()
           join c in results.GetResult<Category>() on p.PostId = c.PostID
           ...
           p.Categories.Add(c)