sonyps4.ru

Crud приложение. Создаем CRUD-приложение с помощью Yii за считанные минуты

Yii – это высокопроизводительный фреймворк, который работает быстро, безопасно и хорошо подходит для приложений Web 2.0.

Он поддерживает приоритет соглашений над конфигурацией, что означает, что если вы следуете руководствам по работе с фреймворком, вы, в конечном итоге, напишите намного меньше кода, чем если бы вы не следовали им (а меньшее количество кода содержит меньшее количество ошибок).

К тому же, фреймворк предлагает много удобных, уже готовых функций, таких как: скаффолдинг, объекты доступа к данным, тематизация, контроль доступа, кэширование и многое другое. В этой статье я расскажу основы того, как используя Yii, создать CRUD систему.

Приступим

Я исхожу из того, что у вас уже установлены и скачайте последнюю стабильную версию (на момент написания статьи – версия 1.1.13).

Распакуйте ZIP-архив, чтобы получить папку yii-1.1.13.e9e4a0 (идентификатор версии может отличаться в зависимости от версии, которую вы загрузили), переименуйте папку в yii, затем поместите ее в ваш корневой каталог, доступный из сети.

В моем случае, это C:wampwww таким образом, путь к файлам фреймворка будет следующим: C:wampwwwyii .

Я буду ссылаться на него как на протяжении всей статьи, поэтому вы можете легко следовать всем шагам, даже если ваши настройки отличаются от моих.

Затем мы должны проверить, какие функции Yii будут поддерживаться нашей системой. Откройте ссылку http://localhost/yii/requirements в вашем браузере, чтобы увидеть детали требований фреймворка.

Поскольку мы будем работать с базой данных MySQL, расширение MYSQL PDO должно быть разрешено.

Мы хотели быстро проверить требования Yii, и поэтому поместили файлы в доступный каталог, но рекомендуется хранить файлы Yii вне сетевого каталога. После проверки можете свободно переместить файлы Yii куда угодно.

Двигаемся дальше

Каждое веб-приложение имеет свою структуру каталога, и Yii приложения также нуждаются в поддержке иерархичной структуры внутри сетевого каталога.

Чтобы создать каркас приложения с подходящей структурой каталога, вы можете использовать Yii инструмент yiic, работающий из командной строки. Перейдите в сетевой каталог и введите следующее:

frameworkyiic webapp yiitest

Эта команда создаст скелет приложения под названием yiitest с минимальным набором необходимых файлов. Внутри вы найдете файл index.php , который служит в качестве скрипта входа, он принимает пользовательские запросы и решает, какой контроллер должен обработать запрос.

Фреймворк Yii основан на принципах MVC и ООП, поэтому вы должны разбираться в этих темах. Если вы не знакомы с MVC, почитайте серию статей The MVC Pattern and PHP , которая предлагает хорошее введение в эту тему.

В Yii URL-адрес выглядит как http://localhost/yiitest/index.php?r=controllerID/actionID . Например, в блоговой системе URL может быть следующим: http://localhost/yiitest/index.php?r=post/create. post – это идентификатор контроллера, а create – идентификатор действия.

Основываясь на идентификаторах, скрипт входа решает, какой контроллер и метод вызвать.

Контроллер, имеющий идентификатор post, должен быть назван PostController (идентификатор получается путем отсечения суффикса Controller от имени класса и изменением первой буквы на строчную).

Идентификатор действия – это идентификатор метода, представленного в контроллере подобным образом; внутри PostController должен быть метод под названием actionCreate() .

Может быть несколько представлений, ассоциированных с одним контроллером, поэтому мы храним файлы представлений внутри папок protected/views/controllerID .

Мы можем создать файл представления для нашего контроллера под названием create.php в описанном выше каталоге, и затем представить его пользователям, просто написав следующий код в actionCreate():

public function actionCreate() { $this->render("create"); }

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

$this->render("create", array("data" => $data_item));

Внутри файла представления мы можем получить доступ к данным через переменную $data.

Представление также имеет доступ к переменной $this , которая указывает на экземпляр контроллера, воспроизводящего представление.

Более того, если вы хотите иметь удобные для пользователя URL-адреса, то можете раскомментировать следующий участок кода в файле protected/config/main.php :

"urlManager"=>array("urlFormat"=>"path", "rules"=>array("/"=>"/view", "//"=>"/", "/"=>"/",)

Тогда URL-адреса будут выглядеть следующим образом: http://localhost/yiitest/controllerID/actionID .

Разработка CRUD приложения

Теперь, когда вы знаете важные соглашения по Yii, пришло время приступить к CRUD. В этой части мы разработаем простую систему, в которой пользователь может выполнять CRUD операции (создание, извлечение, обновление и удаление) с сообщением в блоге.

Шаг 1

Создадим базу данных MySQL под названием yiitest и внутри нее создадим таблицу posts. Таблица будет иметь только три столбца: идентификатор (id ), название (title ) и контент (content ).

CREATE TABLE posts (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100), content TEXT)

Откройте файл конфигурации вашего приложения (protected/config/main.php ) и раскомментируйте следующие строки:

"db"=>array("connectionString" => "mysql:host=localhost;dbname=testdrive, "emulatePrepare" => true, "username" => "root", "password" => "", "charset" => "utf8",)

Замените testdrive на имя вашей базы данных, то есть, yiitest. Также вы должны обеспечить полномочия, необходимые Yii для подключения.

Шаг 2

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

Например, класс Post – это модель для таблицы сообщений. Объект этого класса представляет собой строку из таблицы posts и имеет атрибуты для отражения значений столбцов.

Для того чтобы быстро генерировать модель, мы будем использовать веб-инструмент Yii под названием gii . Этот инструмент может быть использован для генерации моделей, контроллеров и форм для CRUD операций.

Чтобы использовать gii в вашем проекте, найдите следующие строки в файле конфигурации вашего проекта, раскомментируйте их добавьте пароль.

"gii"=>array("class"=>"system.gii.GiiModule", "password"=>your password to access gii, "ipFilters"=>array("127.0.0.1","::1"),)

Затем обратитесь к gii с помощью следующего адреса: http://localhost/yiitest/index.php?r=gii . Если вы используете дружественные пользователю URL-адреса, адрес будет такой: http://localhost/yiitest/gii .

Кликнете на Model Generator. gii попросит вас ввести имя таблицы; введите posts для имени таблицы, а для имени модели используйте Post. Затем кликнете Generate для создания модели.

Проверьте папку protected/models, и вы найдете там файл Post.php.

Шаг 3

Теперь кликнете на CRUD Generator . Введите в качестве имени модели Post. Идентификатор контроллера автоматически заполнится как post.

Это означает, что новый контроллер будет сгенерирован под именем PostController.php .

Кликнете на Generate. Сгенерируется контроллер, а также несколько файлов представления с формами, необходимыми для CRUD операций.

Теперь у вас есть совершенно новое CRUD приложение! Кликнете на ссылку try it now , чтобы протестировать его. Для управления сообщениями вам нужно будет войти как admin/admin .

I am a new SQL Server DBA, I heard of the CRUD acronym, but I do not quite understand the meaning and importance of these CRUD operations, can you please give a detailed explanation?

Solution

CRUD is the basic operations in any RDBMS, and this tip will take a detailed look at the CRUD operations in SQL Server.

What is CRUD?

CRUD means Create, Read, Update, Delete, and it can mean different things in different systems, but for SQL Server, it is commonly considered to map to the following SQL operations on table records.

CRUD SQL
C - Create Insert
R - Read Select
U - Update Update
D - Delete Delete

Here are two examples

In SQL Server 2008, there is a MERGE statement which can achieve the functions of CUD (no R). I purposely omit it here as it is not available across all SQL Server versions and also it is impossible to classify it to C or U or D.

Extending CRUD Concept

CRUD in essence seems to be DML (data manipulation language), but this concept can be extended to DDL (Data Definition Language). For example, if we consider a database as a container, we can CRUD lots of database objects, such as table, view, stored procedure and user, etc. Let’s use a table as an object, we can see the following CRUD actions.

Последнее обновление: 08.04.2017

Большинство операций с данными так или иначе представляют собой CRUD операции (Create, Read, Update, Delete), то есть создание, получение, обновление и удаление. Entity Framework Core позволяет легко выполнять все эти действия.

Для примера создадим проект по типу Console App (.NET Core) . И после создания проекта сразу добавим в него функциональность EF Core. Для этого в проект через NuGet пакеты Microsoft.EntityFrameworkCore.SqlServer и Microsoft.EntityFrameworkCore.Tools .

Затем добавим в проект класс User, объекты которого будут храниться в базе данных:

Public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }

И добавим класс контекста данных ApplicationContext:

Using Microsoft.EntityFrameworkCore; namespace HelloApp { public class ApplicationContext: DbContext { public DbSet Users { get; set; } public ApplicationContext() { Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;"); } } }

Using System; using System.Linq; namespace HelloApp { public class Program { public static void Main(string args) { // Добавление using (ApplicationContext db = new ApplicationContext()) { User user1 = new User { Name = "Tom", Age = 33 }; User user2 = new User { Name = "Alice", Age = 26 }; // Добавление db.Users.Add(user1); db.Users.Add(user2); db.SaveChanges(); } // получение using (ApplicationContext db = new ApplicationContext()) { // получаем объекты из бд и выводим на консоль var users = db.Users.ToList(); Console.WriteLine("Данные после добавления:"); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } // Редактирование using (ApplicationContext db = new ApplicationContext()) { // получаем первый объект User user = db.Users.FirstOrDefault(); if(user!=null) { user.Name = "Bob"; user.Age = 44; //обновляем объект //db.Users.Update(user); db.SaveChanges(); } // выводим данные после обновления Console.WriteLine("\nДанные после редактирования:"); var users = db.Users.ToList(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } // Удаление using (ApplicationContext db = new ApplicationContext()) { // получаем первый объект User user = db.Users.FirstOrDefault(); if (user != null) { //удаляем объект db.Users.Remove(user); db.SaveChanges(); } // выводим данные после обновления Console.WriteLine("\nДанные после удаления:"); var users = db.Users.ToList(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } Console.Read(); } } }

И после выполнения мы получим следующий консольный вывод:

Данные после добавления 1.Tom - 33 2.Alice - 26 Данные после редактирования 1.Bob - 44 2.Alice - 26 Данные после удаления 2.Alice - 26

Добавление

Для добавления объекта используется метод Add , определенный у класса DbSet, в который передается добавляемый объект:

Db.Users.Add(user2); db.SaveChanges();

Метод Add устанавливает значение Added в качестве состояния нового объекта. Поэтому метод db.SaveChanges() сгенерирует выражение INSERT для вставки модели в таблицу.

Если нам надо добавить сразу несколько объектов, то мы можем воспользоваться методом AddRange() :

User user1 = new User { Name = "Tom", Age = 33 }; User user2 = new User { Name = "Alice", Age = 26 }; db.Users.AddRange(user1, user2);

Удаление

Удаление производится с помощью метода Remove :

Db.Users.Remove(user); db.SaveChanges();

Данный метод установит статус объекта в Deleted, благодаря чему Entity Framework при выполнении метода db.SaveChanges() сгенерирует SQL-выражение DELETE.

Если необходимо удалить сразу несколько объектов, то можно использовать метод RemoveRange() :

User user1 = db.Users.FirstOrDefault(); User user2 = db.Users.LastOrDefault(); db.Users.RemoveRange(user1, user2);

Редактирование

При изменении объекта Entity Framework сам отслеживает все изменения, и когда вызывается метод SaveChanges() , будет сформировано SQL-выражение UPDATE для данного объекта, которое обновит объект в базе данных.

Но надо отметить, что в данном случае действие контекста данных ограничивается пределами конструкции using. Но рассмотрим другой пример. Мы получаем объект в одном месте,а обновляем в другом. Например:

User user = null; using (ApplicationContext db = new ApplicationContext()) { // получаем объект user = db.Users.FirstOrDefault(); Console.WriteLine("Данные до редактирования:"); var users = db.Users.ToList(); foreach (User u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } } //................... // Редактирование using (ApplicationContext db = new ApplicationContext()) { // Редактирование if (user != null) { user.Name = "Sam"; user.Age = 33; } db.SaveChanges(); // выводим данные после обновления Console.WriteLine("\nДанные после редактирования:"); var users = db.Users.ToList(); foreach (var u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } }

Несмотря на то, что объект user не равен null, имеется в базе данных, но во втором блоке using обновления соответствующего объекта в БД не произойдет. И в этом случае нам надо использовать метод Update:

// Редактирование using (ApplicationContext db = new ApplicationContext()) { // Редактирование if (user != null) { user.Name = "Sam"; user.Age = 33; db.Users.Update(user); } db.SaveChanges(); // выводим данные после обновления Console.WriteLine("\nДанные после редактирования:"); var users = db.Users.ToList(); foreach (var u in users) { Console.WriteLine($"{u.Id}.{u.Name} - {u.Age}"); } }

При необходимости обновить одновременно несколько объектов, применяется метод UpdateRange() :

Db.Users.UpdateRange(user1, user2);

Связи между сущностями в модели - это отражение реляционных связей между таблицами в БД. Реляционные связи в таблицах реализованы через первичные и внешние ключи, связи в модели Entity на основе навигационных свойств сущностей.

В базе нашего проекта 2 таблицы: Tenants и Apartments. Они связаны отношением «один ко многим». Это значит, что в одной квартире могут проживать несколько жильцов, но один жилец может быть жить только в одной квартире.

На уровне кода (в классах модели) навигационные свойства становятся массивами с ссылками на объекты.

Public class Apartment { public int ApartmentID { get; set; } public decimal ApartСost { get; set; } public int Apartnumber { get; set; } public int NumberofRooms { get; set; } public virtual ICollection Tenants { get; set; } // Массив ссылок на объекты типа Tenant, связанные с этим экземпляром типа Apartment. Навигационное свойство. }

Один класс, становится контейнером для другого.

Три типа загрузки

Существует три типа загрузки связанных данных:

  • отложенная (ленивая);
  • безотложная (прямая);
  • явная.

Они различаются механизмом и производительностью.

При первичной выборке не загружает никакие связанные данные. Они будут загружены только после того, как программист запустит загрузку через навигационное свойство.

Так, если мы попытаемся загрузить данные о квартире с номером 6, то данные о жильцах этой квартиры загружены не будут, это придется делать в два запроса.

Private RegistrationContext db = new RegistrationContext(); // Запрос, извлекающий из таблицы Apartments строку, где в столбце ApartNumber установлено значение 6. Apartment apartment = db.Apartments.Where(n=>n.ApartNumber == 6).FirstOrDefault(); // Второй запрос, извлекающий все объекты Tenant связанные данным объектом Apartment foreach (Tenant t in apartment.Tenants) { // Действия с данными }

Когда идет полная выборка, нам нужны два цикла (один внутри другого):

Foreach (Apartment a in db.Apartments) { foreach(Tenant t in a.Tenants) { // Как-то используем данные. } }

Класс DbContext использует ленивую загрузку по умолчанию. Однако, ленивая загрузка по умолчанию не сработает если:

  • класс модели запечатан (sealed);
  • объявлен с идентификатором доступа отличным от public;
  • навигационное свойство не объявлено виртуальным.

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

Прямая загрузка

Apartments = db.Apartments.Include(t=>t.Tenants) foreach (Apartment a in apartments) { foreach(Tenant t in a.Tenants) { // Как-то используем данные. } }

Хотя в примере выше использованы два цикла, запрос только один.

Допустимо использовать в одной цепочке методов сколько угодно вызовов Include.

Явная загрузка

Похожа на ленивую загрузку. Работает также, но требует явного указания инструкции загрузки (метод Load). Используется если, ленивая загрузка отключена.

В отличие от ленивой, явная загрузка использует для доступа к объекту сущности не свойства контекста (DbSet), а его метод Entry().

Var apartments = db.Apartments.ToList(); foreach (Apartment a in apartments) { // Указываем откуда и что нам нужно загрузить. Конец цепочки - вызов метода Load(). db.Entry(a).Collection(t => t.Tenants).Load(); foreach(Tenant t in a.Tenants) { // Что-то делаем с данными. } }

Обратите внимание на «явность» такого вызова.

  • .db // Объект контекста.
  • .Entry(a) // В параметре объект модели.
  • .Collection(t => t.Tenants) // Метод Collection, потому что навигационное свойство содержит массив ссылок. В параметре делегат, с указанием навигационного свойства.
  • .Load(); //Явный вызов загрузки.

Какую загрузку использовать

Применяйте соответствующую загрузку, пользуясь соображениями производительности. Если вы точно знаете, какие данные нужно отобразить - используйте ленивую загрузку. Если предоставляете выбор пользователю о детальности отображаемой информации, то отложенная - идеальный вариант.

Отложенная загрузка гораздо эффективнее, если требуется контролировать каждый цикл обращений к БД. Если код представляет обработку больших объектов с несколькими навигационными свойствами в каждом, ленивая загрузка, поскольку генерирует большее количество запросов, может вызвать зависание.

Однако, универсального метода тут нет, нужно тестировать каждое приложение для разного размера базы, в том числе и с помощью модульных тестов.

Создание страницы, отображающей информацию о квартирах и проживающих.

Мы собираемся сгенерировать контроллер и GRUD представления с помощью Visual Studio. Для этого в обозревателе решений вызовите контекстное меню на папке Controllers и выберите пункт «Добавить контроллер».

Выберите пункт Контроллер MVC 5 c представлениями, использующий Entity и нажмите «Добавить».

  • класс модели (Apartment);
  • имя контроллера (ApartmentController);
  • и класс контекста (RegistrationContext)

После нажатия «Добавить» Visual Studio сгенерирует вам контроллер с методами действия соответствующим CRUD - инструкциям. Нам предстоит их только поправить.

Наша цель - это страница. Которая может отображать одновременно две таблицы: первая с данными из таблицы Apartmets, вторая - данные из таблицы Tenants, связанные с выделенным элементом из первой таблицы.

Для этого нам понадобится совокупная модель представления включающая данные как из первой, так и из второй таблицы. Cоздадим ее в папке Views/ViewsModels в файле ApartmentIndexer.cs :

Using System.Collections.Generic; using EnrollmentApp.Models; namespace EnrollmentApp.Views.ViewsModel { public class ApartmentIndexer { public IEnumerable Apartments { get; set; } // Свойство для хранения коллекции объектов типа Apartment public IEnumerable Tenants { get; set; } // Свойство для хранения коллекции объектов типа Apartment } }

Чтобы мы могли работать с предыдущим классом в ApartmentController , добавьте в него ссылку на файл:

Using EnrollmentApp.Views.ViewsModel;

Теперь отредактируем метод Index, который будет отображать информацию из двух таблиц.

Public class ApartmentController: Controller { private RegistrationContext db = new RegistrationContext(); // GET: Apartment public ActionResult Index(int? id) { // создаем наш совокупный класс. var IndexModel = new ApartmentIndexer(); // Наполняем его элементами таблицы Apartments. IndexModel.Apartments = db.Apartments .Include(t => t.Tenants) .OrderBy(t => t.Apartnumber); if (id != null) { ViewBag.ApartmentID = id.Value; // Наполняем связанную коллекцию для каждой квартиры соотвествующими жильцами.Чтобы гарантировать, что жилец будет один применяем метод Single // Альтернатива – применить SingeOrDefault IndexModel.Tenants = IndexModel.Apartments.Where(i => i.ApartmentID == id.Value).Single().Tenants; } // Передаем класс-контейнер в представление. return View(IndexModel); } }

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

Осталось исправить представление Index, добавив в него две таблицы ссылки и отобразить данные:

@model EnrollmentApp.Views.ViewsModel.ApartmentIndexer @{ ViewBag.Title = "Квартиры"; }

Index

@Html.ActionLink("Добавить квартиру", "Create")

@foreach (var item in Model.Apartments) { }
Номер квартиры Количество комнат Цена
@Html.DisplayFor(modelItem => item.Apartnumber) @Html.DisplayFor(modelItem => item.NumberofRooms) @Html.DisplayFor(modelItem => item.ApartСost) @Html.ActionLink("Выбрать","Index",new { id = item.ApartmentID}) | @Html.ActionLink("Редактировать", "Edit", new { id=item.ApartmentID }) | @Html.ActionLink("Подробности", "Details", new { id=item.ApartmentID }) | @Html.ActionLink("Удалить", "Delete", new { id=item.ApartmentID })
@if (Model.Tenants != null) {

Жители этой квартиры

@foreach (var item in Model.Tenants) { }
Фамилия Имя и Отчество Дата регистрации
@item.LastName @item.FirstAndMidName @item.RegistrationDate
}

Теперь запустив приложение, перейдите на страницу Index. Страница отображает список квартир:



Загрузка...