Статьи

Создание уровня доступа к данным с использованием Dynamics в WebMatrix

Итак, мы все видели демо-версию WebMatrix, где мы помещаем встроенный SQL на страницу и возвращаем некоторые записи, верно? И я предполагаю, что большинство из вас просто посмотрели на это и подумали: «Юк! Что произойдет, если схема изменится или я захочу получить доступ к одному и тому же набору данных в разных местах? Я хочу, чтобы весь мой код был в одном месте ».

Что ж, мы могли бы потратить пару часов на написание традиционного слоя доступа к данным старой школы, используя классы для представления нашей доменной модели и методов для запроса и сохранения в базе данных и т. Д. И т. Д.…. но так сделал твой папа! Предполагается, что WebMatrix — это крутая, динамичная и быстрая скриптовая штуковина — так что давайте сделаем это динамически … 

Настройка

Прежде всего, давайте создадим базу данных SQL Compact в нашем проекте WebMatrix под названием «Catalog» и дадим ей таблицу с именем «Products» (оригинал, да?):

И мы добавим несколько записей:

И это все, у нас все готово.

 

Способ «5 минут демо»

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

@{
    var db = Database.Open("Catalog");
    var sql = "SELECT * FROM Products";
    var qry = db.Query(sql);
}

<ul>
    @foreach (var product in qry) {
        <li>@product.Name</li>
    }
</ul>

Так в чем проблема? Ну, если бы это был одностраничный сайт, то это вообще не было бы проблемой. Проблема возникает, когда вы хотите получить данные в разных местах на нескольких страницах — это становится кошмаром обслуживания. Котята могут умереть. 

Представьте, что у вас есть код доступа к данным в 20 разных местах на вашем сайте (что является реалистичным числом для небольшого сайта), и вы изменили базу данных или переименовали таблицу продуктов? Что происходит, когда у вас есть запросы по продуктам на нескольких разных страницах, а спецификация изменяется, чтобы включить столбец «inStock», и вам нужно изменить все списки продуктов, чтобы отображать только те элементы, для которых это поле помечено как истинное? Я понимаю, что я, вероятно, «проповедую обращенным» здесь, но вы поняли мою точку зрения.

Вот как это делают крутые дети…

Давайте создадим новый файл Razor в нашей папке App_Code (создайте его, если он еще не существует) с именем ProductsData.cshtml и добавим следующий код:

@using System.Dynamic;

@functions {

    public static Database Catalog {
        get {
            return Database.Open("Catalog");
        }
    }

    public static IEnumerable<dynamic> GetProducts() {
        var sql = "SELECT * FROM Products";
        return Catalog.Query(sql);
    }
}

Теперь, если нам нужно изменить наш список продуктов SQL, нам нужно сделать это только в одном месте, и это значительно облегчает чтение файла представления Razor. Метод GetProducts () возвращает IEnumerable <dynamic>, который в безумном мире динамики связывается во время выполнения, поэтому наше представление теперь выглядит следующим образом:

<ul>
    @foreach(var product in ProductsData.GetProducts()) {
        <li>@product.Name</li>
    }
</ul>

Теперь так лучше! Что еще мы можем сделать? Ну, мы могли бы добавить метод к ProductsData.cshtml, чтобы вытащить один продукт, передав его идентификатор продукта:

public static dynamic GetProductById(int id)
{
    var sql = "SELECT * FROM Products WHERE Id = @0";
    return Catalog.Query(sql, id).Single();
}

Что мы можем использовать, как это на странице содержимого:

@{
    var productId = 1;
    var product = ProductsData.GetProductById(productId);

}

<div>@product.Name - @product.Price</div>

И снова, весь наш код доступа к данным находится в одном месте, и наши страницы содержания намного чище. Мы спасли много котят.

Вставки и обновления

Мы можем достичь тех же преимуществ с помощью вставок и обновлений с небольшим количеством волшебства Expando! Следующий метод в ProductsData.cshtml дает нам вставки:

public static void AddProduct(dynamic product) {
    var sql = "INSERT INTO Products (Name, Description, Price) " +
                "VALUES (@0, @1, @2)";
    Catalog.Execute(sql, product.Name, product.Description, product.Price);
}

Метод имеет один параметр, который принимает динамический. Потрясающая динамика означает, что мы можем передать ему ExpandoObject, чьи члены будут разрешены во время выполнения. Используя динамику таким образом, компилятору просто не важно, может ли он разрешить product.Name, product.Price и т. Д., И он просто оставляет время выполнения для разбора.

На наш взгляд, мы можем получить необходимые нам данные от пользователя в форме «Новый продукт» и использовать метод AddProduct следующим образом:

@using System.Dynamic;
@{
    if(IsPost) {

        dynamic product = new ExpandoObject();
        product.Name = Request["Name"];
        product.Description = Request["Description"];
        product.Price = Request["Price"];

        ProductsData.AddProduct(product);
    }
}

Здесь мы просто создаем новый ExpandoObject, добавляем к нему элементы из отправленных данных формы и передаем его в метод AddProduct. Очень просто.

Обновления достигаются очень похожим образом. Это метод SaveProduct:

public static void SaveProduct(dynamic product) {
    var sql = "UPDATE Products SET Name=@0, Description=@1, Price=@2 WHERE Id=@3";
    Catalog.Execute(sql, product.Name, product.Description, product.Price, product.Id);
}

И это код в представлении:

@using System.Dynamic;
@{
    if(IsPost) {

        dynamic item = new ExpandoObject();
        item.Id = Request["Id"];
        item.Name = Request["Name"];
        item.Description = Request["Description"];
        item.Price = Request["Price"];

        ProductsData.SaveProduct(item);

        Response.Redirect("~/Index.cshtml");
    }
}

Мы снова создаем новый ExpandoObject, добавляем к нему элементы из отправленных данных формы и передаем его методу SaveProduct в ProductData.cshtml.

 

Резюме

Вот так мы можем использовать динамические и Razor @functions для создания простого уровня доступа к данным для наших веб-сайтов WebMatrix. Все котята спасены, время для сна.

Пожалуйста, не стесняйтесь скачать исходный код и посмотреть .