![](https://habrastorage.org/webt/_r/xa/z6/_rxaz6gbce_xm4yazomsaczakpw.png)
تقليديا ، يتم التعبير عن استعلامات OData للبيانات كسلاسل بسيطة دون التحقق من النوع أثناء التجميع أو بدون دعم IntelliSense ، بالإضافة إلى ذلك ، يجب على المطور تعلم بناء جملة لغة الاستعلام. تصف هذه المقالة مكتبة TsToOdata ، التي تحول الاستعلامات إلى بنية لغة ملائمة ويتم تطبيقها بشكل مماثل للفصول والأساليب. يمكنك إنشاء استعلامات مكتوبة باستخدام الكلمات الأساسية TypeScript والعوامل المألوفة.
TsToOdata هي مكتبة لـ TypeScript. وهي مشابهة لـ LINQ لـ C # ، ولكنها ، على عكس الأخيرة ، مخصصة فقط لاستعلامات OData. بالنسبة للمطور الذي يقوم بإنشاء الاستعلامات ، فإن الجزء الأكثر وضوحًا من TsToOdata هو تعبير الاستعلام. تستخدم تعبيرات الاستعلام بناء جملة ، لذلك يكتب المطور ما يجب القيام به ، دون تحديد كيفية القيام بذلك. باستخدام صيغة الاستعلام ، يمكنك تصفية البيانات وتنظيمها وتجميعها من مصدر بيانات ، باستخدام الحد الأدنى من كود البرنامج.
قم بتثبيت TsToOdata
npm install ts2odata
إنشاء نموذج بيانات
بادئ ذي بدء ، نحتاج إلى تعيين مخطط OData لفئات TypeScript.
الخطوة الأولى هي الحصول أولاً على المخطط من EDMX Json. يمكنك استخدام مكتبة OdataToEntity لهذا الغرض .
IEdmModel edmModel;
using (var reader = XmlReader.Create("edmx_schema.xml"))
edmModel = CsdlReader.Parse(reader);
var generator = new OeJsonSchemaGenerator(edmModel);
using (var utf8Json = new MemoryStream())
{
generator.Generate(utf8Json);
utf8Json.Position = 0;
File.WriteAllBytes("json_schema.json", utf8Json.ToArray());
}
Json TypeScript. quicktype.
.
import { EntitySet, OdataContext } from 'ts2odata';
import * as oe from './order';
export class OrderContext extends OdataContext<OrderContext> {
Categories = EntitySet.default<oe.Category>();
Customers = EntitySet.default<oe.Customer>();
OrderItems = EntitySet.default<oe.OrderItem>();
OrderItemsView = EntitySet.default<oe.OrderItemsView>();
Orders = EntitySet.default<oe.Order>();
}
let context: OrderContext = OdataContext.create(OrderContext, 'http://localhost:5000/api');
context.Orders;
context.Orders.select(o => { return { p: o.Name } });
context.Orders.orderby(i => i.Id);
context.Orders.orderbyDescending(i => i.Id);
context.Orders.filter(o => o.Date.getFullYear() == 2016);
context.Orders.expand(o => o.Items);
context.Customers.expand(c => c.Orders).thenExpand(o => o.Items);
context.Orders.orderby(i => i.Id).skip(2);
context.Orders.orderby(i => i.Id).top(3);
context.OrderItems.groupby(i => { return { Product: i.Product } });
context.OrderItems.groupby(i => { return { OrderId: i.OrderId, Status: i.Order.Status } })
.select(g => {
return {
orderId: g.key.OrderId,
avg: g.average(i => i.Price),
dcnt: g.countdistinct(i => i.Product),
max: g.max(i => i.Price),
max_status: g.max(_ => g.key.Status),
min: g.min(i => i.Price),
sum: g.sum(i => i.Price),
cnt: g.count()
}});
context.Customers.key({ Country: 'RU', Id: 1 });
context.OrderItems.key(1, i => i.Order.Customer);
context.OrderItems
.select(i => {
return {
product: i.Product,
Total: i.Count * i.Price,
SumId: i.Id + i.OrderId
}
});
context.Orders.filter(o => o.Items.every(i => i.Price >= 2.1));
context.Orders.filter(o => o.Items.some(i => i.Count > 2));
IN
let items = [1.1, 1.2, 1.3];
context.OrderItems.filter(i => items.includes(i.Price), { items: items });
context.Orders.count();
asEntitySet
context.Orders(o => o.AltCustomer).thenSelect(o => {{
p1: o.Address,
: o.Country,
: o.Id,
: o.Name,
: o.Sex
}}).asEntitySet().orderby(o => o.Id)
GitHub.
, select, expand, groupby — — , , then: thenFilter, thenExpand, thenOrderby, thenOrderbyDescending, thenSkip, thenTop. select thenSelect , , , asEntitySet.
— filter/thenFilter, — select/thenSelect, — groupby , .
let count: number | null = null;
context.OrderItems.filter(i => i.Count == count, { count: count });
let s = {
altCustomerId: 3,
customerId: 4,
dateYear: 2016,
dateMonth: 11,
dateDay: 20,
date: null,
name: 'unknown',
status: "OdataToEntity.Test.Model.OrderStatus'Unknown'",
count1: 0,
count2: null,
price1: 0,
price2: null,
product1: 'unknown',
product2: 'null',
orderId: -1,
id: 1
};
context.Orders.filter(o => o.AltCustomerId == s.altCustomerId &&
o.CustomerId == s.customerId &&
(o.Date.getFullYear() == s.dateYear &&
o.Date.getMonth() > s.dateMonth &&
o.Date.getDay() < s.dateDay ||
o.Date == s.date) &&
o.Name.includes(s.name) &&
o.Status == s.status, s)
.expand(o => o.Items)
.thenFilter(i => (i.Count == s.count1 ||
i.Count == s.count2) &&
(i.Price == s.price1 ||
i.Price == s.price2) &&
(i.Product.includes(s.product1) ||
i.Product.includes(s.product2)) &&
i.OrderId > s.orderId &&
i.Id != s.id, s);
OdataFunctions.stringLength
context.Customers.filter(c => OdataFunctions.stringLength(c.Name) == 5);
OdataFunctions.arrayLength
context.Orders.filter(o => OdataFunctions.arrayLength(o.Items) > 2);
select, filter getQueryUrl toArrayAsync.
getQueryUrl URL . TypeScript:
let url: URL = context.Customers
.expand(c => c.AltOrders).thenExpand(o => o.Items).thenOrderby(i => i.Price)
.expand(c => c.AltOrders).thenExpand(o => o.ShippingAddresses).thenOrderby(s => s.Id)
.expand(c => c.Orders).thenExpand(o => o.Items).thenOrderby(i => i.Price)
.expand(c => c.Orders).thenExpand(o => o.ShippingAddresses).thenOrderby(s => s.Id)
.orderby(c => c.Country).orderby(c => c.Id).getQueryUrl();
OData :
http://localhost:5000/api/Customers?$expand=
AltOrders($expand=Items($orderby=Price),ShippingAddresses($orderby=Id)),
Orders($expand=Items($orderby=Price),ShippingAddresses($orderby=Id))
&$orderby=Country,Id
toArrayAsync Json. TypeScript:
context.Customers
.expand(c => c.Orders).thenSelect(o => { return { Date: o.Date } }).orderby(o => o.Date)
.asEntitySet().select(c => { return { Name: c.Name } }).orderby(c => c.Name).toArrayAsync();
Json:
[{
"Name": "Ivan",
"Orders": [{
"Date": "2016-07-04T19:10:10.8237573+03:00"
}, {
"Date": "2020-02-20T20:20:20.000002+03:00"
}
]
}, {
"Name": "Natasha",
"Orders": [{
"Date": "2016-07-04T19:10:11+03:00"
}
]
}, {
"Name": "Sasha",
"Orders": []
}, {
"Name": "Unknown",
"Orders": [{
"Date": null
}
]
}
]
, , toArrayAsync OdataParser:
import { OdataParser } from 'ts2odata';
import schema from './schema.json';
let odataParser = new OdataParser(schema);
context.Orders.toArrayAsync(odataParser);
(enum)
OData (Namespace), :
let context: OrderContext = OdataContext.create(OrderContext, 'http://localhost:5000/api', 'OdataToEntity.Test.Model');
في بعض الحالات ، قد يكون من الضروري إنشاء كائن OdataParser لترجمة التعدادات بشكل صحيح .
import { OdataParser } from 'ts2odata';
import schema from './schema.json';
let odataParser = new OdataParser(schema);
let context: OrderContext = OdataContext.create(OrderContext, 'http://localhost:5000/api', 'OdataToEntity.Test.Model', odataParser);
مصدر
كود المصدر موجود على جيثب .
في المجلد المصدر - رمز عقدة الحزمة ، في مجلد الاختبار - الاختبارات.
آمل أن يكون مشروع TsToOdata مفيدًا لك وأن يوفر عليك من روتين كتابة التعليمات البرمجية الرتيبة.