Ez a fejezet a RecroGrid Framework adatbázis kezelésének alapvető beállításait mutatja be.
A RecroGrid Framework adatbázis kezelése, az Entity Framework által generált logikai modell, és a
DbContext segítségével került megvalósításra.
A konfigurációs beállításban megadható az alapértelmezett adatbázis connection és
modell/context, de az egyes entitások külön modellben, vagy adatbázisban is szerepelhetnek, amit paraméterezéssel
lehet megadni. A RecroGrid Framework teljesen kompatibilis a code-first típusú adatbázis kezelést használó alkalmazásokkal.
Az entitásokat azok első használatuknál a RecroGrid Framework automatikusan legenerálja az Entity Framework logikai modell alapján.
A mezők tulajdonságait a RecroGridRGProperty tárolja.
Az itt beállított paraméterek határozzák meg, hogy a mező értéke milyen forrásból szerezhető be, hogyan kell megjeleníteni
Lista és Form nézetben, milyen kapcsolatban áll más mezőkkel, entitásokkal. A tulajdonságokat az Adminisztrátor futásidőben tudja
módosítani egy erre kialakított webes felületen.
Mezők definiálása logikai modell alapján
A ColName tartalmazza az entitás mezőjének nevét
a logikai modell alapján. Adatbázis használatánál ez egyenértékű egy adott tábla egy oszlopával.
A neveknek Alias is adható,
ami kifejezések, duplikált mezők vagy szerencsétlenül elnevezett mezők esetén különösen hasznos. A felhasználók számára a
ColTitle tulajdonság
jelenik meg, amit javasolt RecroDict szótárban kezelni,
ez az Adminisztrátori funkciókban automatikusan legenerálható.
A megjelenítendő mezőket, illetve azok pozícióját és szélességét futásidőben a felületen lehet állítgatni, és felhasználónkét
külön el lehet menteni, az Adminisztrátor pedig az alapértelmezést tudja beállítani.
A Readable tulajdonság meghatározza, hogy a felhasználó
megjelenítheti-e List nézetben a mezőt. Azokat a mezőket, amiket a megjelenítéstől
függetlenül mindig be kell olvasni az adatbázisból, azokat az RGO_Forced
opciós paraméterben kell jelezni. A RecroGrid teljes funkcionalitásának használatához az entitásokban a kulcs mezőket az
IsKey tulajdonsággal kell ellátni.
Security Note
A kulcs mezők beállítástól függetlenül mindig kiküldésre kerülnek, ezért olyan entitások esetén ahol a kulcs mező nem nyilvános
adat (ez logikailag is hibás) létre kell hozni egy külön kulcs mezőt. Javasolt mindig egyoszlopos kulcs kialakítása,
a többoszlopos kulcsok létrehozása kerülendő. Mivel a kulcsok a további műveletek egyik azonosítóját
képezik, a kliensre küldés előtt a RecroGrid ezeket digitális aláírással látja el. Az egyes mezők nevének kiküldése
szintén biztonsági kockázatot jelent, ezért a RecroGrid kliensoldalon egy automatikusan generált
ClientName névvel azonosítja a mezőket.
A felületeken megjelenő ColTitle
tulajdonság hiánya esetén a RecroGrid azt a ColName tulajdonságból próbálja előállítani.
A teljes mezőszintű és adatfüggő jogosultsági rendszerhez javasolt a RecroSec használata.
Many to One (*-1 vagy *-0..1) kapcsolat esetén a ColName-ben
csak meg kell adni a logikai modell szerinti útvonalat,
és a rendszer automatikusan összekapcsolja a táblákat a definiált kapcsolatok alapján. Megfelelő kapcsolatok esetén a mező
lehet akár több entitás távolságra is.
Ha a külső mező EntityBase tulajdonsága beállításra
kerül, akkor öröklődnek az opciós beállítások a ColTitle
és a ClientName tulajdonságok,
így a Listákban az azonos mezők egyforma stílusban jelennek meg. Az aktuális mezőhöz definiált opciók az örökölteket felülírják.
Az öröklés az RGO_DisableInheritance
opciós paraméterrel letiltható.
Caution
Opciók öröklése esetén, a eredeti mező dinamikus stílusainak megvalósítása nagyobb odafigyelést igényel,
mivel egy másik entitáshoz kapcsolva a saját entitásában található mezők nem léteznek, azokat külön fel kell venni.
Lehetőség van One to Many (1-*) kapcsolatú mezők megadására is, amit a RecroGrid Framework automatikusan felismer, és egy vesszővel szeparált
felsorolást ad vissza. Ennek megjelenítése kliens és szerveroldalon egyaránt testre szabható.
SQL
--ColName: műfajok meghatározása egy film listában
ESQL:(select value g.Name from {0}.Genre as g)
Tip
A One to Many kapcsolatok automatikus használata csak kisebb rekordszám esetén javasolt, mert lényegesen csökkenhet a
teljesítmény, és megnőhet az adatforgalom. Nagyobb rekordszám (vagy nagyobb forgalom) esetén javasolt az ilyen mezőket
szerveroldalon külön feltölteni.
Ha a névben csak egy külső entitás neve (aminek a logikai modellben a kapcsolata definiált) szerepel,
akkor az entitás összes oszlopa beolvasásra kerül.
A mező nevének egy speciális RG_Self nevű adat is megadható, ami típusosan beolvassa az
összes oszlopot, ami az aktuális entitásban (logikai modellben) megtalálható. Ezt a mezőt
Entity típusúnak kell definiálni.
Note
Az RG_Self mező az RGO_Forced
opcióval ellátva azt eredményezi, hogy a beállításoktól függetlenül az entitás összes mezője mindig beolvasásra kerül.
Ez hasznos lehet egy bonyolultabb szerveroldali funkcionalitáshoz, aminek szüksége van mindig (majdnem) minden adatra.
.NET Core verzió esetén az RG_Self nem elérhető.
A RecroGrid által automatikusan generált adatbázis lekérdezések
--ColName: Person.FirstName
--Employee entitásban hivatkozás Person entitás mezőre
SELECT Extent1.*, Extent2.FirstName FROM [Employee] AS [Extent1] INNER JOIN [Person] AS [Extent2] ON [Extent1].[BusinessEntityID] = [Extent2].[BusinessEntityID]
--ColName: Employee.LoginID
--Person entitásban hivatkozás Employee entitás mezőre
SELECT Extent1.*, Extent2.LoginID FROM [Person] AS [Extent1] LEFT OUTER JOIN [Employee] AS [Extent2] ON [Extent1].[BusinessEntityID] = [Extent2].[BusinessEntityID]
--ColName: RecroGrid_Property.RecroGrid_Entity.Name
--RecroGrid_Options entitásban hivatkozás RecroGrid_Entity mezőre
SELECT Extent1.*, Extent3.Name FROM [RecroGrid_Options] AS [Extent1] LEFT OUTER JOIN [RecroGrid_Property] AS [Extent2] ON [Extent1].[PropertyId] = [Extent2].[PropertyId]
LEFT OUTER JOIN [RecroGrid_Entity] AS [Extent3] ON [Extent2].[EntityId] = [Extent3].[EntityId]
EF logikai modellben nem szereplő kapcsolatok definiálása
Az olyan külső mezők esetén, amik a logikai modell alapján közvetlenül nem elérhetőek, a kapcsolatot manuálisan kell felépíteni.
Ennek megvalósítására két opciós beállítás áll rendelkezésre az
RGO_InnerJoin és az
RGO_OuterJoin.
A opciók hatására az SQL INNER JOIN és LEFT OUTER JOIN lekérdezésnek
megfelelő eredmények érhetők el, paraméterezésük megegyezik.
Az opcióban kifejezést a külső tábla nevétől kezdődően kell megadni, a feltételeknél
NSQL formátum használandó.
A külső táblának mindenképpen Alias-t kell adni, és a névben azzal együtt és NSQL: előtaggal kell hivatkozni.
Az aktuális tábla nevénél a {0} jelölés használandó.
SQL Join
ColName: NSQL:personExt.FirstName
RGO_InnerJoin: Person personExt on {0}.BusinessEntityID = personExt.BusinessEntityID
ColName: NSQL:category.ProductCategoryID
RGO_OuterJoin: ProductCategory category on {0}.ProductSubcategory.ProductCategoryID = category.ProductCategoryID
RGF Core: ColName: NSQL:category.ProductCategoryID
RGO_OuterJoin: ProductCategory category on [{0}.ProductSubcategory].ProductCategoryID = category.ProductCategoryID
Note
.NET Core verzió esetén NSQL előtagot kell használni, illetve
többszintű kapcsolat esetén a táblaneveket szögletes zárójellel jelölni kell [{0}.T1.Tx] formában.
Entity/Native SQL - egyedi kifejezések
A mezők definiálásakor lehetőség van SQL kifejezések meghatározására is, amiket a RecroGrid beilleszt a adatbázis lekérdezésekbe.
Ezeket ESQL: előtaggal kell jelölni, és ESQL szabványnak megfelelően kell megadni. Ezen mezőknek kötelező
Alias-t megadni.
Note
.NET Core verzió esetén az ESQL kifejezés nem elérhető, helyette natív SQL kifejezéseket kell megadni NSQL előtaggal.
SQL kifejezések a mezők definiálására
--Alias: FullName
--case when, concat kifejezések
ESQL:Concat(case when {0}.Suffix is null then '' else Concat({0}.Suffix, ' ') end,
Concat(case when {0}.Title is null then '' else Concat({0}.Title, ' ') end,
Concat(Concat({0}.FirstName, ' '),
Concat(case when {0}.MiddleName is null then '' else Concat({0}.MiddleName, ' ') end,
{0}.LastName))))
--Alias: Exp
ESQL:concat(concat(cast({0}.CreditCard.ExpMonth as System.String), '/'),
cast({0}.CreditCard.ExpYear as System.String))
--Alias: OrderCount
--Subquery: count(*)
ESQL:max(select value Count(o.ProductID) from {0}.Order_Details as o)
--Alias: PhotoId
--Subquery: (many to one)
ESQL:max(select value p.ProductPhotoID from {0}.ProductProductPhoto as p
where p.ProductID ={0}.ProductID and p.Primary=true)
--Alias: LastStatus
--Subquery (many to many)
ESQL:max(select value top(1) poh.Status from PurchaseOrderHeader as poh
where poh.PurchaseOrderID={0}.PurchaseOrderID order by poh.OrderDate desc)
--Alias: two
--konstans érték
ESQL:(2)
--Alias: PreExp
--ESQL Canonical Function
ESQL:AddDays(Expiration, 6)
Az NSQL:EntityBase. előtag használatával az NSQL típusú mező örökölhető az EntityBase
azonos Alias
mezőjéből, így az NSQL kifejezést csak egyszer kell megadni.
Ha az útvonal egynél több entitást tartalmaz, akkor az útvonalat is ki kell írni.
NSQL kifejezés öröklése másik entitásból
--Person entitás FullName alias mezőjének öröklése
NSQL:EntityBase.FullName
--OrderDetails-ben a CategoryName (két entitás távolság)
NSQL:EntityBase.Products.Categories.CategoryName
Adatbázisban tárolt képek
Lehetőség van (bár nem javasolt) adatbázisban binárisan tárolni a képeket, amit a RecroGrid egy szerviz
segítségével aszinkron módon külön lekérdezésekben képes beolvasni. Ebben az esetben a
ListType-ot Image-re, a
FormType-ot pedig ImageInDB-re
kell állítani. A kliensen megjelenő IMG tag forrása egy felparaméterezett szerviz hívásra fog mutatni,
amit a RecroGrid lekezel.
Ha a kép egy másik entitásban van, akkor a ColName-ben
a külső entitás kulcsát (oszlop nevét) kell megadni NSQL hivatkozással, (mert a külön adatbázis lekérdezéshez arra van szükség) a kép mező nevét
pedig az RGO_ImageTarget opciós beállításban.
A RecroGrid a képeket az entitás verziójával is ellátja, az RGO_ImageVersion opciós paraméterben
definiált mező értékével, vagy ha ilyen nincs, akkor a globális beállítás szerinti RowVersionName
mező értékével.
Dinamikus (adatbázisban nem létező) adatok kezelése
A dinamikus mezőket az IsDynamic
kapcsolóval kell megjelölni, és tetszőleges nevet lehet adni. Ezek a mezők nem kerülnek bele az adatbázis műveletekbe,
értékük futásidőben szerveroldalon és
kliensoldalon is megadható.
Ha FormType típusa RecroDict,
akkor a mező értéke közvetlen RecroDict szótár elem is lehet, akár az entitás egy mezőjének értékével paraméterezve.
Az SQL lekérdezés WHERE feltételeit több automatizmus is szabályozhatja.
A különböző típusú szűrők AND kapcsolatban állnak, tehát minden szűrő egy újabb szűkítő feltétel,
amit egy másik szűrő nem képes felülbírálni. Azonban lehetőség van az SQL lekérdezés vagy szűrés teljesen manuális létrehozására is.
Az első szintű szűrés a felületről kapott szűrő, amit a RecroGrid Framework a
UserFilter
tulajdonságba tölt be. Ezt a szűrőt a felhasználó szabadon állíthatja az erre kialakított webes felületen. Az Adminisztrátornak
lehetősége van a felületen beállított szűrőt alapértelmezett szűrőnek elmenteni, ami az
RGO_UserFilter opciós paraméterbe kerül.
Lehetőség van szerveroldalon futásidőben definiált szűrők megadására is, amit a
FixFilter tulajdonságban lehet beállítani.
Ezeket tipikusan a manuálisan állított környezetfüggő szűrők.
C#
//Only the data of the current user
FixFilter.Add(this, RGFilter.LogicalOperatorEnum.And, "UserId", RGFilter.SQLOperatorEnum.Equal, RecroSec.GetCurrentUserId(rgContext.HttpContext));
//A separate filter object for a parenthesized condition
RGFilter user1 = new RGFilter();
user1.Add(this, RGFilter.LogicalOperatorEnum.Or, "FromUserId", RGFilter.SQLOperatorEnum.Equal, RecroSec.GetCurrentUserId(rgContext.HttpContext));
user1.AddAliasCol(this, RGFilter.LogicalOperatorEnum.Or, "ToUserID", RGFilter.SQLOperatorEnum.Equal, RecroSec.GetCurrentUserId(rgContext.HttpContext));
FixFilter.Add(RGFilter.LogicalOperatorEnum.And, user1);
A RecroGrid futásidőben automatikusan létrehoz környezetfüggő szűröket, ilyen az egymásból nyíló listák esetén
a Parent/Child kapcsolat, illetve választás esetén a kezdő szűrő feltétel.
Az entitáshoz a RGO_FixWhere
opcióban definiálható további NSQL formátumú fix szűrő is.
SQL
{0}.Status='Valid'
exists(select * from {0}.Users A where A.Status = 'Valid')
Végül a lapozási információk kerülnek a szűrőbe, illetve RecroSec használatánál esetleges
jogosultsági szűrők.
Az NSQL típusú mezőknél (pl. subquery) előfordulhat, hogy a szűrés használatához a eredmény típusát is
definiálni kell, amit az RGO_SystemType
opciós beállításba kell beírni. Alapértelmezés szerint ha
ListType=Numeric vagy
FormType=DropDown,ListBox
akkor Int64 egyébként String.
Mezőnként lehetőség van egyedi szűrő kifejezés megadására, ami képes beépülni, a felhasználó által a felületen megadható szűrő rendszerbe.
Ilyen szűrő tipikusan egy One to Many kapcsolat, ahol egy subquery tartalmazza a szűrést. A feltételt
NSQL formátumban kell megadni az
RGO_FilterExpression opciós paraméterben.
SQL
--A ColName egy subquery-t tartalmaz, aminek az eredménye egy felsorolás
ESQL:(select value g.Name from {0}.Genre as g)
--Az RGO_FilterExpression egy feltételt tartalmaz, amiben a {1} helyére a felhasználó a szűrési felületen a ColName-ben meghatározott
--lekérdezés eredményéből tud majd választani. A rendszer a szűrésnek megfelelő (equal, in, not in ...) műveleteket automatikusan berakja.
exists(select g from {0}.GenreList as g where g.GenreId {1})
--A fenti szűréshez az GenreList mezőt kötelezőnek kell beállítani: RGO_Forced=true
Rendezés
Az adatbázis lekérdezést a felhasználó tetszés szerint akár több oszlop szerint rendezheti. A rendezést felhasználónként el lehet
menteni. Az Adminisztrátor a rendezést alapértelmezésnek tudja menteni, ami az
RGO_Sort opciós beállításba kerül.
Lapozás
List nézetben a RecroGrid az adatokat blokkokban olvassa be az adatbázisból, amit lapozásnak hívunk.
Az RGO_ItemsPerPage opciós paraméterben
megadható, hogy a felhasználónak egyszerre mennyi sor látszódjon, az
RGO_Preload paraméterben pedig, hogy az
adatbázis lekérdezés esetén mennyi rekord kerüljön beolvasásra. Alapértelmezés szerint az RGO_Preload kétszerese az RGO_ItemsPerPage-nek,
ami azt jeleni, hogy minden második lapozás esetén kell az adatbázishoz fordulni. Az összes beolvasott (beállítások szerint) adat
kiküldésre kerül a kliensnek, és ott tárolásra (cache) kerül, tehát előre lapozás után a visszafelé lapozás már nem jár adatbázis
művelettel. Az RGO_Resizable opció
beállításával a felhasználónak lehetősége van a Lista átméretezésére, aminek hatására az egyszerre megjelenő adatok mennyisége
megváltozhat.
Szótár típusú mezők megjelenítése
A RecroGrid egyik legkényelmesebb funkciója a Szótár kezelés, ami paraméterek alapján automatizálni tudja List nézetben a
megjelenítést és szűrést, Form dialógusokon pedig a felvitelt/módosítást. Szótárként kezelendő mezőnek azt nevezzük, ahol egy
külső listából választással kerül tárolásra az elem azonosítója. A külső lista lehet egy adatbázis tábla, statikus felsorolás vagy
bármilyen egyéb lista, ami kulcs/megnevezés formában leírható. Ezeknek a mezőknek a
FormType típusát DropDown-ra
kell állítani. A különböző használati módok az RGO_DictionaryItems
opciós paraméterben lehet beállítani.
Tip
Javasolt Entitás szinten megadni szótárakat, ami utána minden hivatkozásnál egységesen használható, nem kell külön mezőnként felvenni.
Néhány tucatnál nagyobb elemszámú listát nem javasolt szótárként kezelni, mert az jelenősen ronthatja a teljesítményt. Ilyenkor
javasolt külön adatbázis táblát használni, és List nézetben azzal összekötni, Form nézetben pedig külső listából választani.
A legegyszerűbb beállítás az RGO_DictionaryItems
opcióban a statikus felsorolás. A felsorolást kapcsos zárójelek között kell megadni, a kulcsot az értéktől kettősponttal,
az elemeket pontosvesszővel kell elválasztani. White-space karakterek levágásra kerülnek. Az érték lehet RecroDict
szótár elem is
<%%>Scope.StringId formátumban.
Ha a kulcsban vagy a megnevezésben kettőspont vagy pontosvessző szerepel, akkor a RecroDict megoldást kell használni.
A statikus listák helyett lényegesen jobb megoldás a RecroDict
használata. A RecroDict számos előnye közül ebben az esetben nagyon jól jön, hogy támogatja a többnyelvű megjelenítést,
kliens és szerveroldalon is kódból függvényeken keresztül elérhető, így egyéb feladatokra is használható.
Adatbázisban tárolja az adatokat, ami online szerkeszthető és saját gyorsítótárral rendelkezik.
Az RGO_DictionaryItems opciós paraméterben
meg kell adni a szótár Scope azonosítóját a <%%> előtaggal.
A <%%>KK: előtag esetén pedig Kulcs/Megnevezés páros helyett, Kulcs/Kulcs párokat generál.
Az RGO_DictionaryItems-ben egy NSQL formátumú lekérdezést is lehet megadni, ami egy Kulcs/Megnevezés
párosból álló listát ad vissza. A lekérdezést NSQL: előtaggal kell jelölni.
A lekérdezés szűrhető az aktuális rekord mezőinek értékeit felhasználva. Az egyes mezőkre a @ClientName
jelöléssel lehet hivatkozni.
SQL
NSQL:select e.PropertyId, e.ColName from RecroGrid_Property e where e.EntityId=@rg-col-31
Callback
Lehetőség van szerveroldalon megvalósított függvény dinamikus meghívására, amit a RGO_DictionaryItems
paraméterben a
Callback:functionName formátumban kell megadni. A függvény definíciója
public static List<KeyValuePair<string, string="">> functionName(RGProperty, EntityObject, ObjectContext)
kell hogy legyen. A függvényt először az aktuális RecroGrid-ben keresi, ha ott nem létezik, akkor aktuális
RecroGrid entitás típusában, ha ott sem, akkor az EntityBase típusú RecroGrid-ben és végül az
EntityBase-ben használt entitás típusában.
Ha egy Entitás szótárként kezelhető, akkor javasolt annak az entitásnak beállítani az RGO_DictionaryItems opciós
paramétert, így minden hivatkozás automatikusan és egységesen működik. Az Entitásra beállítható szótár a mezőknél alkalmazható
beállításokon kívül egy egyszerűsített query formátum is megadható Id,Name[,Order] formában,
ami egy SQL lekérdezést készít az Entitás-ra. A harmadik paraméter opcionális, ami a rendezést határozza meg.