Professional Documents
Culture Documents
Пример 1. колоквијума
Задатак
Креирати (локалну) базу података под називом ShopDB у оквиру које треба да
постоји табела Products са колонама:
Id (int, autoincrement, PK),
Name (nvarchar, NOT NULL),
Description (nvarchar, NULL),
Price (decimal, NOT NULL).
SQL код за базу података ставити заједно са Solution-ом у текстуални фајл.
Пре овога можемо обрисати постојећи код за креирање табеле, или испод тог
кода додати овај, а у другом случају код који желимо да се изврши морамо
селектовати, и након тога изаберемо на десни клик опцију као на слици, након чега
ћемо добити приказ свих производа из базе.
2. Креирање апликације
Одаберемо у менијима ставку File > New > Project, изаберемо .NET Core у левом
панелу и потом у десном ASP.NET Core Web Application, као на следећој слици.
За локацију одабрати фолдер који сте креирали на десктопу.
Након клика на OK тастер добија се дијалог као на следећој слици.
Одабрати API или Web API (зависи од инсталације VS2017), искључити подршку
за SSL (Configure for HTTPS), и потом кликнути на тастер OK. У Solution Explorer
панелу добијамо приказ као на следећој слици.
Сада у DataLayer пројекту креирамо фолдер Models (десни клик мишем > Add >
New Folder) и у том фолдеру креирамо једну класу (десни клик > Add > Class) и
назовемо је Product.
Сада у класи додамо атрибуте које представљају еквиваленте колона у табели
базе, при чему за саму класу ставимо да је јавна.
Сада треба додати код ProductRepository класи. Додајемо прво конекциони стринг:
private string ConnectionString =
"Server=(localdb)\\mssqllocaldb;Database=ShopDB;Trusted_Connection=True;
MultipleActiveResultSets=true";
Конекциони стринг се може прекопирати из неког од постојећих пројеката и
преправити (промени се назив базе и евентуално сервера ако има потребе).
Сада креирамо методу GetAllProducts(), с тим што ћемо прво креирати интерфејс
за ову класу, под називом IProductRepository. Из контекстног менија за DataLayer
одаберемо Add > New Item, и изаберемо из понуђених ставки Interface, који назовемо
IProductRepository. Интерфејс мора бити јаван, и садржи декларације свих метода
које имплементира ProductRepository класа, а које морају бити доступне вишим
слојевима апликације (јер се за DI користи интерфејс класе, а не сама класа).
Тако се добија код за IPRoductRepository.cs
using DataLayer.Models;
using System;
using System.Collections.Generic;
using System.Text;
namespace DataLayer
{
public interface IProductRepository
{
List<Product> GetAllProducts();
}
}
Код за методу GetAllProducts() урадимо аналогно као код примера са вежби, при
чему је за SQL потребно додати одговарајућу библиотеку, као на следећој слици, а
такође ProductRepository класа имплементира интерфејс IProductRepository.
Дакле, према ранијим примера, код за ProductRepository класу је:
public class ProductRepository : IProductRepository
{
private string ConnectionString =
"Server=(localdb)\\mssqllocaldb;Database=ShopDB;Trusted_Connection=Tru
e;MultipleActiveResultSets=true";
while (dataReader.Read())
{
Product product = new Product();
product.Id = dataReader.GetInt32(0);
product.Name = dataReader.GetString(1);
product.Description = dataReader.GetString(2);
product.Price = dataReader.GetDecimal(3);
listToReturn.Add(product);
}
}
return listToReturn;
}
}
Овде ће се касније појавити један проблем, а то је читање поља из базе која могу
бити празна (NULL поља) и за која при уносу података није задата никаква вредност.
То се може решити тако што за та поља уместо методе GetString() или друге за
одговарајући тип податка, користимо методу GetValue() и проверимо да ли је враћена
вредности null или одговарајућег типа (string и сл.).
На колоквијуму можете једноставно у та поља увек унети неку вредност.
return command.ExecuteNonQuery();
}
}
Касније ћемо Data слој допунити додатним кодом, ако буде потребе, а сада
прелазимо на креирање слоја пословне логике.
4. Креирање Business слоја
Истим поступком као за Data слој креирамо Business слој, који ћемо назвати
BusinessLayer, а аутоматски креирану класу преименујемо у ProductBusiness.
Први корак је да креирамо „везу“ ка Data слоју, користећи DI, као у следећем
коду:
using DataLayer;
using DataLayer.Models;
using System;
using System.Collections.Generic;
namespace BusinessLayer
{
public class ProductBusiness
{
private IProductRepository productRepository;
namespace BusinessLayer
{
public interface IProductBusiness
{
List<Product> GetAllProducts();
}
}
Остаје да још додамо код за методу која прослеђује Data слоју захтеве за упис у
базу, а која је слична одговарајућој методи у ранијим примерима који су рађени на
вежбама, тј. у интерфејс класу додајемо:
bool InsertProduct(Product product);
а у ProductBusiness класу:
public bool InsertProduct(Product product)
{
if(this.productRepository.InsertProduct(product) > 0)
{
return true;
}
else
{
return false;
}
}
InsertProduct је типа Boolean јер вишем слоју враћамо само податак о томе да ли
је упис у базу успешан или није, што је погодније за обраду на API слоју и frontend
апликацији.
На овом слоју ће бити потребно и креирати апликацију која враћа производе чија
је цена између задате минималне и максималне цене. То можемо урадити ефикасно
користећи FindAll() методу, за коју је документација дата на следећем линку:
https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-
1.findall?view=netcore-2.2
Као аргумент FindAll() методе навешћемо логичке услове да је цена производа
мања од максимално задате и већа од минимално задате цене, тј.
public List<Product> GetMinMaxPriceProducts(int minprice, int maxprice)
{
List<Product> products =
this.productRepository.GetAllProducts();
Затим додамо код за подразумевану GET методу, при чему треба имати у виду да
се у задатку и за приказ свих производа захтева посебна адреса, тј. на руту
контролера треба додати у путањи getall, што се може постићи на два начина,
додавањем Route[] декоратора методе, или аргументом саме HTTP методе, као што је
урађено у следећем коду:
[HttpGet("getall")]
public List<Product> GetAllProducts()
{
return this.productBusiness.GetAllProducts();
}
Остала је још метода за приказ производа чија је цена између две задате цене.
Задате цене се прослеђују као вредности у оквиру URL-а, а задају се у декоратору
HttpGet као у следећем коду:
[HttpGet("{minprice}/{maxprice}/get")]
public List<Product> GetMinMaxPriceProduct(int minprice, int
maxprice)
{
return
this.productBusiness.GetMinMaxPriceProducts(minprice, maxprice);
}
6. Конфигурација
Пре него што компајлирамо апликацију, потребно је у Startup.cs класи
инџектоване интерфејс класе декларисати као сервисе у оквиру ConfigureServices
методе, као у следећем коду:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_
2_2);
services.AddScoped<IProductBusiness, ProductBusiness>();
services.AddScoped<IProductRepository,
ProductRepository>();
}
У случају да имате проблема са верзијом .NET Core SDK, тј. да је на рачунару нпр.
верзија 2.0 уместо верзије 2.2, морате уклонити прву декларацију у наведеној методи
којом се декларише ниво компатибилности са одговарајућом верзијом .NET Core.
7. Тестирање апликације
Након претходно описаног поступка компајлирамо/покренемо апликацију,
након чега се у веб прегледачу приказује подразумевани контролер. Позивањем
одговарајуће руте за приказ свих производа, добијамо приказ као на следећој слици.
За унос производа користимо Postman алат, а пошто се подаци о производу шаљу
у оквиру тела HTTP захтева, Postman треба подесити као на следећој слици, па се
након извршавања захтева добија позитиван одговор (true).
Након уноса неколико производа, можемо поново позвати методу за приказ свих
производа, након чега добијамо:
Ако сада позовемо руту за приказ производа из опсега задатих цена, добијамо
приказ као на следећој слици.
8. Закључак
Апликација успешно ради, што смо проверили „тестирањем“, али, као што смо
раније напоменули, може доћи до проблема ако не унесемо опис производа у базу.
Међутим, то се може догодити само ако производ уносимо директно у базу, ако унос
производа вршимо преко апликације, у случају изостављања описа у базу ће бити
уписан празан стринг, као на следећој слици:
тако да се поновним приказом свих производа може видети да нема проблема са
приказом производа који немају никакав опис.
USE [ShopDB]
GO
SET QUOTED_IDENTIFIER ON
GO