├── .gitignore
├── .vscode
├── launch.json
└── tasks.json
├── AspNetCore_OData.postman_collection.json
├── README.md
├── aspnet-core-web-api-using-odata.sln
├── docker-compose.yml
├── postman.JPG
└── src
└── OData.WebApi
├── Controllers
├── BaseController.cs
├── OData
│ ├── ODataBaseController.cs
│ ├── ProductCategoryODataController.cs
│ └── ProductODataController.cs
├── ProductCategoryController.cs
└── ProductController.cs
├── Data
├── Entities
│ ├── Base
│ │ └── BaseEntity.cs
│ ├── Product.cs
│ └── ProductCategory.cs
├── Migrations
│ ├── 20191030195859_init.Designer.cs
│ ├── 20191030195859_init.cs
│ └── ProductDbContextModelSnapshot.cs
├── ProductDbContext.cs
├── Repositories
│ ├── IRepository.cs
│ └── Repository.cs
└── TypeConfigurations
│ ├── ProductCategoryTypeConfiguration.cs
│ └── ProductTypeConfiguration.cs
├── Dto
├── ProductCategoryDto.cs
└── ProductDto.cs
├── OData.WebApi.csproj
├── Program.cs
├── Properties
└── launchSettings.json
├── Startup.cs
└── appsettings.json
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
254 | # Logs
255 | Logs*
256 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": ".NET Core Launch (web)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | "program": "${workspaceFolder}/src/OData.WebApi/bin/Debug/netcoreapp2.2/OData.WebApi.dll",
13 | "args": [],
14 | "cwd": "${workspaceFolder}/src/OData.WebApi",
15 | "stopAtEntry": false,
16 | "serverReadyAction": {
17 | "action": "openExternally",
18 | "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)"
19 | },
20 | "env": {
21 | "ASPNETCORE_ENVIRONMENT": "Development"
22 | },
23 | "sourceFileMap": {
24 | "/Views": "${workspaceFolder}/Views"
25 | }
26 | },
27 | {
28 | "name": ".NET Core Attach",
29 | "type": "coreclr",
30 | "request": "attach",
31 | "processId": "${command:pickProcess}"
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/src/OData.WebApi/OData.WebApi.csproj"
11 | ],
12 | "problemMatcher": "$tsc"
13 | },
14 | {
15 | "label": "publish",
16 | "command": "dotnet",
17 | "type": "process",
18 | "args": [
19 | "publish",
20 | "${workspaceFolder}/src/OData.WebApi/OData.WebApi.csproj"
21 | ],
22 | "problemMatcher": "$tsc"
23 | },
24 | {
25 | "label": "watch",
26 | "command": "dotnet",
27 | "type": "process",
28 | "args": [
29 | "watch",
30 | "run",
31 | "${workspaceFolder}/src/OData.WebApi/OData.WebApi.csproj"
32 | ],
33 | "problemMatcher": "$tsc"
34 | }
35 | ]
36 | }
--------------------------------------------------------------------------------
/AspNetCore_OData.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "9a64ed14-4419-4fe2-a636-e341bd37e44c",
4 | "name": "Dotnet_Conf_OData",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6 | },
7 | "item": [
8 | {
9 | "name": "Product",
10 | "item": [
11 | {
12 | "name": "Get",
13 | "item": [
14 | {
15 | "name": "GetAll",
16 | "request": {
17 | "method": "GET",
18 | "header": [],
19 | "url": {
20 | "raw": "localhost:5000/odata/products",
21 | "host": [
22 | "localhost"
23 | ],
24 | "port": "5000",
25 | "path": [
26 | "odata",
27 | "products"
28 | ]
29 | }
30 | },
31 | "response": []
32 | },
33 | {
34 | "name": "GetById",
35 | "request": {
36 | "method": "GET",
37 | "header": [
38 | {
39 | "key": "Content-Type",
40 | "value": "application/json",
41 | "type": "text"
42 | }
43 | ],
44 | "url": {
45 | "raw": "localhost:5000/odata/products(6d42ac79-2b65-460d-9991-22b86ad66fb9)",
46 | "host": [
47 | "localhost"
48 | ],
49 | "port": "5000",
50 | "path": [
51 | "odata",
52 | "products(6d42ac79-2b65-460d-9991-22b86ad66fb9)"
53 | ]
54 | }
55 | },
56 | "response": []
57 | },
58 | {
59 | "name": "Filter",
60 | "request": {
61 | "method": "GET",
62 | "header": [],
63 | "url": {
64 | "raw": "localhost:5000/odata/products?$filter=price gt 10000",
65 | "host": [
66 | "localhost"
67 | ],
68 | "port": "5000",
69 | "path": [
70 | "odata",
71 | "products"
72 | ],
73 | "query": [
74 | {
75 | "key": "$filter",
76 | "value": "price gt 10000"
77 | }
78 | ]
79 | }
80 | },
81 | "response": []
82 | },
83 | {
84 | "name": "SkipTake",
85 | "request": {
86 | "method": "GET",
87 | "header": [],
88 | "url": {
89 | "raw": "localhost:5000/odata/products?$count=true&$top=5&$skip=1",
90 | "host": [
91 | "localhost"
92 | ],
93 | "port": "5000",
94 | "path": [
95 | "odata",
96 | "products"
97 | ],
98 | "query": [
99 | {
100 | "key": "$count",
101 | "value": "true"
102 | },
103 | {
104 | "key": "$top",
105 | "value": "5"
106 | },
107 | {
108 | "key": "$skip",
109 | "value": "1"
110 | }
111 | ]
112 | }
113 | },
114 | "response": []
115 | },
116 | {
117 | "name": "OrderByAsc",
118 | "request": {
119 | "method": "GET",
120 | "header": [],
121 | "url": {
122 | "raw": "localhost:5000/odata/products?$orderby=price",
123 | "host": [
124 | "localhost"
125 | ],
126 | "port": "5000",
127 | "path": [
128 | "odata",
129 | "products"
130 | ],
131 | "query": [
132 | {
133 | "key": "$orderby",
134 | "value": "price"
135 | }
136 | ]
137 | }
138 | },
139 | "response": []
140 | },
141 | {
142 | "name": "OrderByDesc",
143 | "request": {
144 | "method": "GET",
145 | "header": [],
146 | "url": {
147 | "raw": "localhost:5000/odata/products?$orderby=price desc",
148 | "host": [
149 | "localhost"
150 | ],
151 | "port": "5000",
152 | "path": [
153 | "odata",
154 | "products"
155 | ],
156 | "query": [
157 | {
158 | "key": "$orderby",
159 | "value": "price desc"
160 | }
161 | ]
162 | }
163 | },
164 | "response": []
165 | },
166 | {
167 | "name": "FilterProductNameContains",
168 | "request": {
169 | "method": "GET",
170 | "header": [],
171 | "url": {
172 | "raw": "localhost:5000/odata/products?$filter=contains(productname, 'LG')",
173 | "host": [
174 | "localhost"
175 | ],
176 | "port": "5000",
177 | "path": [
178 | "odata",
179 | "products"
180 | ],
181 | "query": [
182 | {
183 | "key": "$filter",
184 | "value": "contains(productname, 'LG')"
185 | }
186 | ]
187 | }
188 | },
189 | "response": []
190 | },
191 | {
192 | "name": "FilterBySubProperty",
193 | "request": {
194 | "method": "GET",
195 | "header": [],
196 | "url": {
197 | "raw": "localhost:5000/odata/products?$expand=category($filter=categoryName eq 'TV')",
198 | "host": [
199 | "localhost"
200 | ],
201 | "port": "5000",
202 | "path": [
203 | "odata",
204 | "products"
205 | ],
206 | "query": [
207 | {
208 | "key": "$expand",
209 | "value": "category($filter=categoryName eq 'TV')"
210 | }
211 | ]
212 | }
213 | },
214 | "response": []
215 | },
216 | {
217 | "name": "OnlyCount",
218 | "request": {
219 | "method": "GET",
220 | "header": [],
221 | "url": {
222 | "raw": "localhost:5000/odata/products?$top=0&$count=true",
223 | "host": [
224 | "localhost"
225 | ],
226 | "port": "5000",
227 | "path": [
228 | "odata",
229 | "products"
230 | ],
231 | "query": [
232 | {
233 | "key": "$top",
234 | "value": "0"
235 | },
236 | {
237 | "key": "$count",
238 | "value": "true"
239 | }
240 | ]
241 | }
242 | },
243 | "response": []
244 | },
245 | {
246 | "name": "SelectFields",
247 | "request": {
248 | "method": "GET",
249 | "header": [],
250 | "url": {
251 | "raw": "localhost:5000/odata/products?$select=id,productname",
252 | "host": [
253 | "localhost"
254 | ],
255 | "port": "5000",
256 | "path": [
257 | "odata",
258 | "products"
259 | ],
260 | "query": [
261 | {
262 | "key": "$select",
263 | "value": "id,productname"
264 | }
265 | ]
266 | }
267 | },
268 | "response": []
269 | },
270 | {
271 | "name": "Expand",
272 | "request": {
273 | "method": "GET",
274 | "header": [],
275 | "url": {
276 | "raw": "localhost:5000/odata/products?$expand=category",
277 | "host": [
278 | "localhost"
279 | ],
280 | "port": "5000",
281 | "path": [
282 | "odata",
283 | "products"
284 | ],
285 | "query": [
286 | {
287 | "key": "$expand",
288 | "value": "category"
289 | }
290 | ]
291 | }
292 | },
293 | "response": []
294 | },
295 | {
296 | "name": "ExpandAndSelect",
297 | "request": {
298 | "method": "GET",
299 | "header": [],
300 | "url": {
301 | "raw": "localhost:5000/odata/products?$expand=category($select=categoryName)&$select=id,productName",
302 | "host": [
303 | "localhost"
304 | ],
305 | "port": "5000",
306 | "path": [
307 | "odata",
308 | "products"
309 | ],
310 | "query": [
311 | {
312 | "key": "$expand",
313 | "value": "category($select=categoryName)"
314 | },
315 | {
316 | "key": "$select",
317 | "value": "id,productName"
318 | }
319 | ]
320 | }
321 | },
322 | "response": []
323 | }
324 | ],
325 | "_postman_isSubFolder": true
326 | },
327 | {
328 | "name": "Post",
329 | "request": {
330 | "method": "POST",
331 | "header": [
332 | {
333 | "key": "Content-Type",
334 | "value": "application/json",
335 | "type": "text"
336 | }
337 | ],
338 | "body": {
339 | "mode": "raw",
340 | "raw": "{\n \"productName\": \"Sony 65-Inch\",\n \"categoryId\": \"1236a458-0802-4340-bdd4-05859c9aaaad\",\n \"description\": \"Sony 65-Inch 4K Ultra HD Smart LED TV\",\n \"price\": 10000,\n \"weight\": 70\n}"
341 | },
342 | "url": {
343 | "raw": "localhost:5000/odata/products",
344 | "host": [
345 | "localhost"
346 | ],
347 | "port": "5000",
348 | "path": [
349 | "odata",
350 | "products"
351 | ]
352 | }
353 | },
354 | "response": []
355 | },
356 | {
357 | "name": "Delete",
358 | "request": {
359 | "method": "DELETE",
360 | "header": [],
361 | "url": {
362 | "raw": "localhost:5000/odata/products/0100b063-f8db-4ba5-936c-b3d623cebde5",
363 | "host": [
364 | "localhost"
365 | ],
366 | "port": "5000",
367 | "path": [
368 | "odata",
369 | "products",
370 | "0100b063-f8db-4ba5-936c-b3d623cebde5"
371 | ]
372 | }
373 | },
374 | "response": []
375 | },
376 | {
377 | "name": "Put",
378 | "request": {
379 | "method": "PUT",
380 | "header": [
381 | {
382 | "key": "Content-Type",
383 | "value": "application/json",
384 | "type": "text"
385 | }
386 | ],
387 | "body": {
388 | "mode": "raw",
389 | "raw": " {\n \"id\": \"010b34c3-5d91-4f15-a926-a4edbc3a9770\",\n \"name\": \"Lenovo Thinkpad - YENİİİİİİİİİİ2222\",\n \"categoryId\": \"a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0\",\n \"description\": \"Lenovo Thinkpad Laptop\",\n \"price\": 2800,\n \"weight\": 1.7\n }"
390 | },
391 | "url": {
392 | "raw": "localhost:5000/odata/products",
393 | "host": [
394 | "localhost"
395 | ],
396 | "port": "5000",
397 | "path": [
398 | "odata",
399 | "products"
400 | ]
401 | }
402 | },
403 | "response": []
404 | }
405 | ]
406 | },
407 | {
408 | "name": "Product_Category",
409 | "item": [
410 | {
411 | "name": "Get",
412 | "item": [
413 | {
414 | "name": "GetAll",
415 | "request": {
416 | "method": "GET",
417 | "header": [],
418 | "url": {
419 | "raw": "localhost:5000/odata/products",
420 | "host": [
421 | "localhost"
422 | ],
423 | "port": "5000",
424 | "path": [
425 | "odata",
426 | "products"
427 | ]
428 | }
429 | },
430 | "response": []
431 | },
432 | {
433 | "name": "GetById",
434 | "request": {
435 | "method": "GET",
436 | "header": [
437 | {
438 | "key": "Content-Type",
439 | "value": "application/json",
440 | "type": "text"
441 | }
442 | ],
443 | "url": {
444 | "raw": "localhost:5000/odata/product_categories(1236a458-0802-4340-bdd4-05859c9aaaad)",
445 | "host": [
446 | "localhost"
447 | ],
448 | "port": "5000",
449 | "path": [
450 | "odata",
451 | "product_categories(1236a458-0802-4340-bdd4-05859c9aaaad)"
452 | ]
453 | }
454 | },
455 | "response": []
456 | },
457 | {
458 | "name": "OnlyCount",
459 | "request": {
460 | "method": "GET",
461 | "header": [],
462 | "url": {
463 | "raw": "localhost:5000/odata/product_categories?$top=0&$count=true",
464 | "host": [
465 | "localhost"
466 | ],
467 | "port": "5000",
468 | "path": [
469 | "odata",
470 | "product_categories"
471 | ],
472 | "query": [
473 | {
474 | "key": "$top",
475 | "value": "0"
476 | },
477 | {
478 | "key": "$count",
479 | "value": "true"
480 | }
481 | ]
482 | }
483 | },
484 | "response": []
485 | }
486 | ],
487 | "_postman_isSubFolder": true
488 | },
489 | {
490 | "name": "Post",
491 | "request": {
492 | "method": "POST",
493 | "header": [
494 | {
495 | "key": "Content-Type",
496 | "value": "application/json",
497 | "type": "text"
498 | }
499 | ],
500 | "body": {
501 | "mode": "raw",
502 | "raw": "{\n \"categoryName\":\"My Category\"\n}"
503 | },
504 | "url": {
505 | "raw": "localhost:5000/odata/product_categories",
506 | "host": [
507 | "localhost"
508 | ],
509 | "port": "5000",
510 | "path": [
511 | "odata",
512 | "product_categories"
513 | ]
514 | }
515 | },
516 | "response": []
517 | },
518 | {
519 | "name": "Delete",
520 | "request": {
521 | "method": "DELETE",
522 | "header": [],
523 | "url": {
524 | "raw": "localhost:5000/odata/product_categories/833507f4-958c-469e-8615-5993df3b53fe",
525 | "host": [
526 | "localhost"
527 | ],
528 | "port": "5000",
529 | "path": [
530 | "odata",
531 | "product_categories",
532 | "833507f4-958c-469e-8615-5993df3b53fe"
533 | ]
534 | }
535 | },
536 | "response": []
537 | },
538 | {
539 | "name": "Put",
540 | "request": {
541 | "method": "PUT",
542 | "header": [
543 | {
544 | "key": "Content-Type",
545 | "type": "text",
546 | "value": "application/json"
547 | }
548 | ],
549 | "body": {
550 | "mode": "raw",
551 | "raw": " {\n \"id\": \"9eebe71d-d58c-462c-882f-5241b860211e\",\n \"name\": \"My category update\"\n }"
552 | },
553 | "url": {
554 | "raw": "localhost:5000/odata/product_categories",
555 | "host": [
556 | "localhost"
557 | ],
558 | "port": "5000",
559 | "path": [
560 | "odata",
561 | "product_categories"
562 | ]
563 | }
564 | },
565 | "response": []
566 | }
567 | ]
568 | }
569 | ],
570 | "event": [
571 | {
572 | "listen": "prerequest",
573 | "script": {
574 | "id": "b9ccdc18-8a58-4f39-915e-abb42055dca8",
575 | "type": "text/javascript",
576 | "exec": [
577 | ""
578 | ]
579 | }
580 | },
581 | {
582 | "listen": "test",
583 | "script": {
584 | "id": "006bf3f6-b431-4b5a-8959-8a889a2e354c",
585 | "type": "text/javascript",
586 | "exec": [
587 | ""
588 | ]
589 | }
590 | }
591 | ],
592 | "protocolProfileBehavior": {}
593 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Presentation : https://speakerdeck.com/suadev/add-odata-support-to-asp-dot-net-core-web-api
2 |
3 | This repo aims to show that how easily OData can be added to your existing/new Asp.Net Core Web Api to perform all CRUD operations.
4 |
5 | This is a simple api that consist of two entities called Product and ProductCategory.
6 |
7 | localhost:5000/api/products -> classic rest endpoint
8 |
9 | localhost:5000/odata/products -> odata rest endpoint
10 |
11 | You can check following sample OData queries and results.
12 |
13 | if you like Postman, just import AspNetCore_OData.postman_collection.json file and you will see more sample query in Get folders.
14 |
15 |
16 |
17 |
18 | #### Get All Categories - http://localhost:5000/odata/product_categories?$count=true
19 |
20 | ```javascript
21 | {
22 | "@odata.context": "http://localhost:5000/odata/$metadata#product_categories",
23 | "@odata.count": 3,
24 | "value": [
25 | {
26 | "id": "1236a458-0802-4340-bdd4-05859c9aaaad",
27 | "categoryName": "Headphones"
28 | },
29 | {
30 | "id": "8b726886-e719-413c-a125-939ee5af387d",
31 | "categoryName": "TV"
32 | },
33 | {
34 | "id": "a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0",
35 | "categoryName": "Computers"
36 | }
37 | ]
38 | }
39 | ```
40 |
41 |
42 | #### Get All Products - http://localhost:5000/odata/products?$count=true
43 |
44 | ```javascript
45 | {
46 | "@odata.context": "http://localhost:5000/odata/$metadata#products",
47 | "@odata.count": 3,
48 | "value": [
49 | {
50 | "id": "6d42ac79-2b65-460d-9991-22b86ad66fb9",
51 | "productName": "JBL Tune",
52 | "categoryId": "1236a458-0802-4340-bdd4-05859c9aaaad",
53 | "description": "JBL Tune 500BT On-Ear",
54 | "price": 15,
55 | "weight": 0.3
56 | },
57 | {
58 | "id": "78a4a7db-073f-4ad9-a157-2a9da0ceae38",
59 | "productName": "HP Zbook",
60 | "categoryId": "a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0",
61 | "description": "HP Zbook Laptop",
62 | "price": 2000,
63 | "weight": 3
64 | },
65 | {
66 | "id": "aec7ce71-bfa6-4b0f-8aef-78816a31c9fa",
67 | "productName": "LG 32-Inch",
68 | "categoryId": "8b726886-e719-413c-a125-939ee5af387d",
69 | "description": "LG 32-Inch 720p LED TV",
70 | "price": 12000,
71 | "weight": 60
72 | }
73 | ]
74 | }
75 | ```
76 |
77 |
78 | #### Get Product by ID - http://localhost:5000/odata/products(010b34c3-5d91-4f15-a926-a4edbc3a9770)
79 |
80 | ```javascript
81 | {
82 | "@odata.context": "http://localhost:5000/odata/$metadata#products/$entity",
83 | "id": "6d42ac79-2b65-460d-9991-22b86ad66fb9",
84 | "productName": "JBL Tune",
85 | "categoryId": "1236a458-0802-4340-bdd4-05859c9aaaad",
86 | "description": "JBL Tune 500BT On-Ear",
87 | "price": 15,
88 | "weight": 0.3
89 | }
90 | ```
91 |
92 |
93 | #### Filter by Price (price greater than 10000) - http://localhost:5000/odata/products?$filter=price%20gt%2010000
94 |
95 | ```javascript
96 | {
97 | "@odata.context": "http://localhost:5000/odata/$metadata#products",
98 | "value": [
99 | {
100 | "id": "aec7ce71-bfa6-4b0f-8aef-78816a31c9fa",
101 | "productName": "LG 32-Inch",
102 | "categoryId": "8b726886-e719-413c-a125-939ee5af387d",
103 | "description": "LG 32-Inch 720p LED TV",
104 | "price": 12000,
105 | "weight": 60
106 | }
107 | ]
108 | }
109 | ```
110 |
111 |
112 | #### Order by Price - http://localhost:5000/odata/products?$orderby=price
113 |
114 | ```javascript
115 | {
116 | "@odata.context": "http://localhost:5000/odata/$metadata#products",
117 | "value": [
118 | {
119 | "id": "6d42ac79-2b65-460d-9991-22b86ad66fb9",
120 | "productName": "JBL Tune",
121 | "categoryId": "1236a458-0802-4340-bdd4-05859c9aaaad",
122 | "description": "JBL Tune 500BT On-Ear",
123 | "price": 15,
124 | "weight": 0.3
125 | },
126 | {
127 | "id": "78a4a7db-073f-4ad9-a157-2a9da0ceae38",
128 | "productName": "HP Zbook",
129 | "categoryId": "a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0",
130 | "description": "HP Zbook Laptop",
131 | "price": 2000,
132 | "weight": 3
133 | },
134 | {
135 | "id": "aec7ce71-bfa6-4b0f-8aef-78816a31c9fa",
136 | "productName": "LG 32-Inch",
137 | "categoryId": "8b726886-e719-413c-a125-939ee5af387d",
138 | "description": "LG 32-Inch 720p LED TV",
139 | "price": 12000,
140 | "weight": 60
141 | }
142 | ]
143 | }
144 | ```
145 |
146 |
147 | #### Skip & Take - http://localhost:5000/odata/products?$count=true&$top=2&$skip=1
148 |
149 | ```javascript
150 | {
151 | "@odata.context": "http://localhost:5000/odata/$metadata#products",
152 | "@odata.count": 3,
153 | "value": [
154 | {
155 | "id": "78a4a7db-073f-4ad9-a157-2a9da0ceae38",
156 | "productName": "HP Zbook",
157 | "categoryId": "a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0",
158 | "description": "HP Zbook Laptop",
159 | "price": 2000,
160 | "weight": 3
161 | },
162 | {
163 | "id": "aec7ce71-bfa6-4b0f-8aef-78816a31c9fa",
164 | "productName": "LG 32-Inch",
165 | "categoryId": "8b726886-e719-413c-a125-939ee5af387d",
166 | "description": "LG 32-Inch 720p LED TV",
167 | "price": 12000,
168 | "weight": 60
169 | }
170 | ]
171 | }
172 | ```
173 |
174 |
175 | #### Get Product Count - http://localhost:5000/odata/products?$top=0&$count=true
176 |
177 | ```javascript
178 | {
179 | "@odata.context": "http://localhost:5000/odata/$metadata#products",
180 | "@odata.count": 3,
181 | "value": []
182 | }
183 | ```
184 |
185 |
186 | #### Select Specific Fields - http://localhost:5000/odata/products?$select=id,productname
187 |
188 | ```javascript
189 | {
190 | "@odata.context": "http://localhost:5000/odata/$metadata#products(id,productName)",
191 | "value": [
192 | {
193 | "id": "6d42ac79-2b65-460d-9991-22b86ad66fb9",
194 | "productName": "JBL Tune"
195 | },
196 | {
197 | "id": "78a4a7db-073f-4ad9-a157-2a9da0ceae38",
198 | "productName": "HP Zbook"
199 | },
200 | {
201 | "id": "aec7ce71-bfa6-4b0f-8aef-78816a31c9fa",
202 | "productName": "LG 32-Inch"
203 | }
204 | ]
205 | }
206 | ```
207 |
208 |
209 | #### Expand with CategoryGroup - http://localhost:5000/odata/products?$expand=category
210 |
211 | ```javascript
212 | {
213 | "@odata.context": "http://localhost:5000/odata/$metadata#products",
214 | "value": [
215 | {
216 | "id": "6d42ac79-2b65-460d-9991-22b86ad66fb9",
217 | "productName": "JBL Tune",
218 | "categoryId": "1236a458-0802-4340-bdd4-05859c9aaaad",
219 | "description": "JBL Tune 500BT On-Ear",
220 | "price": 15,
221 | "weight": 0.3,
222 | "category": {
223 | "id": "1236a458-0802-4340-bdd4-05859c9aaaad",
224 | "categoryName": "Headphones"
225 | }
226 | },
227 | {
228 | "id": "78a4a7db-073f-4ad9-a157-2a9da0ceae38",
229 | "productName": "HP Zbook",
230 | "categoryId": "a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0",
231 | "description": "HP Zbook Laptop",
232 | "price": 2000,
233 | "weight": 3,
234 | "category": {
235 | "id": "a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0",
236 | "categoryName": "Computers"
237 | }
238 | },
239 | {
240 | "id": "aec7ce71-bfa6-4b0f-8aef-78816a31c9fa",
241 | "productName": "LG 32-Inch",
242 | "categoryId": "8b726886-e719-413c-a125-939ee5af387d",
243 | "description": "LG 32-Inch 720p LED TV",
244 | "price": 12000,
245 | "weight": 60,
246 | "category": {
247 | "id": "8b726886-e719-413c-a125-939ee5af387d",
248 | "categoryName": "TV"
249 | }
250 | }
251 | ]
252 | }
253 | ```
254 |
255 |
256 | #### Expand with CategoryGroup and Select - http://localhost:5000/odata/products?$expand=category($select=categoryName)&$select=id,productName
257 |
258 | ```javascript
259 | {
260 | "@odata.context": "http://localhost:5000/odata/$metadata#products(id,productName,category(categoryName))",
261 | "value": [
262 | {
263 | "id": "6d42ac79-2b65-460d-9991-22b86ad66fb9",
264 | "productName": "JBL Tune",
265 | "category": {
266 | "categoryName": "Headphones"
267 | }
268 | },
269 | {
270 | "id": "78a4a7db-073f-4ad9-a157-2a9da0ceae38",
271 | "productName": "HP Zbook",
272 | "category": {
273 | "categoryName": "Computers"
274 | }
275 | },
276 | {
277 | "id": "aec7ce71-bfa6-4b0f-8aef-78816a31c9fa",
278 | "productName": "LG 32-Inch",
279 | "category": {
280 | "categoryName": "TV"
281 | }
282 | }
283 | ]
284 | }
285 | ```
286 |
287 |
288 | ### Running Locally
289 |
290 | - docker-comppose up (for postgres instance)
291 | - dotnet run
292 |
293 |
294 |
295 | ### Migration
296 |
297 | - dotnet ef migrations add "init" -c ProductDbContext -p src/OData.WebApi --output-dir Data/Migrations
298 |
--------------------------------------------------------------------------------
/aspnet-core-web-api-using-odata.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26124.0
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{13F32673-540E-4553-B723-6823F01DA296}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OData.WebApi", "src\OData.WebApi\OData.WebApi.csproj", "{63C6CBC9-3E0E-4593-A801-A9023E10F664}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Debug|x86 = Debug|x86
15 | Release|Any CPU = Release|Any CPU
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Debug|x64.ActiveCfg = Debug|Any CPU
26 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Debug|x64.Build.0 = Debug|Any CPU
27 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Debug|x86.ActiveCfg = Debug|Any CPU
28 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Debug|x86.Build.0 = Debug|Any CPU
29 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Release|x64.ActiveCfg = Release|Any CPU
32 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Release|x64.Build.0 = Release|Any CPU
33 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Release|x86.ActiveCfg = Release|Any CPU
34 | {63C6CBC9-3E0E-4593-A801-A9023E10F664}.Release|x86.Build.0 = Release|Any CPU
35 | EndGlobalSection
36 | GlobalSection(NestedProjects) = preSolution
37 | {63C6CBC9-3E0E-4593-A801-A9023E10F664} = {13F32673-540E-4553-B723-6823F01DA296}
38 | EndGlobalSection
39 | EndGlobal
40 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 | services:
3 | postgres:
4 | image: postgres:10.6-alpine
5 | container_name: odata_postgres
6 | ports:
7 | - "5436:5432"
8 | environment:
9 | - POSTGRES_DB=OData
10 | - POSTGRES_USER=postgres
11 | - POSTGRES_PASSWORD=postgres
--------------------------------------------------------------------------------
/postman.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/suadev/aspnet-core-web-api-using-odata/df83d62d6ee939e626e04cf0b56d0a271731c454/postman.JPG
--------------------------------------------------------------------------------
/src/OData.WebApi/Controllers/BaseController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Mapster;
5 | using Microsoft.AspNet.OData;
6 | using Microsoft.AspNetCore.Mvc;
7 | using OData.WebApi.Data.Entities;
8 | using OData.WebApi.Data.Repositories;
9 |
10 | namespace Pms.Api.Controllers
11 | {
12 | [ApiController]
13 | public class BaseController : ControllerBase
14 | where TEntity : BaseEntity
15 | {
16 | private readonly IRepository _repository;
17 | public BaseController(IRepository repository)
18 | {
19 | _repository = repository;
20 | }
21 | public IActionResult Get()
22 | {
23 | return Ok(_repository.Query().ProjectToType());
24 | }
25 |
26 | [HttpGet("({id})")]
27 | public virtual SingleResult Get([FromODataUri] Guid id)
28 | {
29 | var entity = _repository.Query().Where(q => q.Id.Equals(id)).ProjectToType();
30 | return SingleResult.Create(entity);
31 | }
32 |
33 | [HttpPost]
34 | public virtual async Task Post([FromBody] TEntity entity)
35 | {
36 | _repository.Add(entity);
37 | await _repository.SaveChangesAsync();
38 | return Ok();
39 | }
40 |
41 | [HttpPut]
42 | public virtual async Task Put([FromBody] TEntity entity)
43 | {
44 | if (await _repository.IsExistAsync(entity.Id) == false)
45 | {
46 | return NotFound();
47 | }
48 |
49 | _repository.Update(entity);
50 | await _repository.SaveChangesAsync();
51 | return Ok();
52 | }
53 |
54 | [HttpDelete("{id}")]
55 | public virtual async Task Delete(Guid id)
56 | {
57 | if (await _repository.IsExistAsync(id) == false)
58 | {
59 | return NotFound();
60 | }
61 |
62 | _repository.Delete(id);
63 | await _repository.SaveChangesAsync();
64 | return Ok();
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Controllers/OData/ODataBaseController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNet.OData;
5 | using Microsoft.AspNet.OData.Routing;
6 | using Microsoft.AspNetCore.Mvc;
7 | using OData.WebApi.Data.Entities;
8 | using OData.WebApi.Data.Repositories;
9 |
10 | namespace Pms.Api.Controllers
11 | {
12 | public class ODataBaseController : ODataController
13 | where TEntity : BaseEntity
14 | {
15 | private readonly IRepository _repository;
16 | public ODataBaseController(IRepository repository)
17 | {
18 | _repository = repository;
19 | }
20 |
21 | [ODataRoute]
22 | [EnableQuery(PageSize = 2)]
23 | public IActionResult Get()
24 | {
25 | return Ok(_repository.Query());
26 | }
27 |
28 | [ODataRoute("({id})")]
29 | [EnableQuery]
30 | public virtual SingleResult Get([FromODataUri] Guid id)
31 | {
32 | var entity = _repository.Query().Where(q => q.Id.Equals(id));
33 | return SingleResult.Create(entity);
34 | }
35 |
36 | [ODataRoute()]
37 | public virtual async Task Post([FromBody] TEntity entity)
38 | {
39 | _repository.Add(entity);
40 | await _repository.SaveChangesAsync();
41 | return Ok();
42 | }
43 |
44 | [ODataRoute]
45 | [HttpPut]
46 | public virtual async Task Put([FromBody] TEntity entity)
47 | {
48 | if (await _repository.IsExistAsync(entity.Id) == false)
49 | {
50 | return NotFound();
51 | }
52 |
53 | _repository.Update(entity);
54 | await _repository.SaveChangesAsync();
55 | return Ok();
56 | }
57 |
58 | [ODataRoute("{id}")]
59 | [HttpDelete()]
60 | public virtual async Task Delete(Guid id)
61 | {
62 | if (await _repository.IsExistAsync(id) == false)
63 | {
64 | return NotFound();
65 | }
66 |
67 | _repository.Delete(id);
68 | await _repository.SaveChangesAsync();
69 | return Ok();
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Controllers/OData/ProductCategoryODataController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNet.OData.Routing;
2 | using OData.WebApi.Data.Entities;
3 | using OData.WebApi.Data.Repositories;
4 |
5 | namespace Pms.Api.Controllers.OData
6 | {
7 | [ODataRoutePrefix("product_categories")]
8 | public class ProductCategoryODataController : ODataBaseController
9 | {
10 | public ProductCategoryODataController(IRepository productCategoryRepository)
11 | : base(productCategoryRepository)
12 | {
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Controllers/OData/ProductODataController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNet.OData.Routing;
2 | using OData.WebApi.Data.Entities;
3 | using OData.WebApi.Data.Repositories;
4 |
5 | namespace Pms.Api.Controllers.OData
6 | {
7 | [ODataRoutePrefix("products")]
8 | public class ProductODataController : ODataBaseController
9 | {
10 | public ProductODataController(IRepository productRepository)
11 | : base(productRepository)
12 | {
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Controllers/ProductCategoryController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using OData.WebApi.Data.Entities;
3 | using OData.WebApi.Data.Repositories;
4 | using OData.WebApi.Dto;
5 |
6 | namespace Pms.Api.Controllers.OData
7 | {
8 | [Route("api/product_categories")]
9 | public class ProductCategoryController : BaseController
10 | {
11 | public ProductCategoryController(IRepository productRepository)
12 | : base(productRepository)
13 | {
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Controllers/ProductController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using OData.WebApi.Data.Entities;
3 | using OData.WebApi.Data.Repositories;
4 | using OData.WebApi.Dto;
5 |
6 | namespace Pms.Api.Controllers.OData
7 | {
8 | [Route("api/products")]
9 | public class ProductController : BaseController
10 | {
11 | public ProductController(IRepository productRepository)
12 | : base(productRepository)
13 | {
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Entities/Base/BaseEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OData.WebApi.Data.Entities
4 | {
5 | public class BaseEntity
6 | {
7 | public Guid Id { get; set; }
8 | public DateTime CreatedDate { get; set; }
9 | public string CreatedBy { get; set; }
10 | public DateTime? UpdatedDate { get; set; }
11 | public string UpdatedBy { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Entities/Product.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OData.WebApi.Data.Entities
4 | {
5 | public class Product : BaseEntity
6 | {
7 | public string ProductName { get; set; }
8 | public Guid CategoryId { get; set; }
9 | public ProductCategory Category { get; set; }
10 | public string Description { get; set; }
11 | public decimal Price { get; set; }
12 | public double Weight { get; set; }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Entities/ProductCategory.cs:
--------------------------------------------------------------------------------
1 | namespace OData.WebApi.Data.Entities
2 | {
3 | public class ProductCategory : BaseEntity
4 | {
5 | public string CategoryName { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Migrations/20191030195859_init.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Migrations;
6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
8 | using OData.WebApi.Data;
9 |
10 | namespace OData.WebApi.Data.Migrations
11 | {
12 | [DbContext(typeof(ProductDbContext))]
13 | [Migration("20191030195859_init")]
14 | partial class init
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
21 | .HasAnnotation("ProductVersion", "2.2.4-servicing-10062")
22 | .HasAnnotation("Relational:MaxIdentifierLength", 63);
23 |
24 | modelBuilder.Entity("OData.WebApi.Data.Entities.Product", b =>
25 | {
26 | b.Property("Id")
27 | .ValueGeneratedOnAdd();
28 |
29 | b.Property("CategoryId");
30 |
31 | b.Property("CreatedBy")
32 | .ValueGeneratedOnAdd()
33 | .HasDefaultValue("skose");
34 |
35 | b.Property("CreatedDate")
36 | .ValueGeneratedOnAdd()
37 | .HasDefaultValue(new DateTime(2019, 10, 30, 22, 58, 59, 249, DateTimeKind.Local).AddTicks(675));
38 |
39 | b.Property("Description");
40 |
41 | b.Property("Price");
42 |
43 | b.Property("ProductName");
44 |
45 | b.Property("UpdatedBy");
46 |
47 | b.Property("UpdatedDate");
48 |
49 | b.Property("Weight");
50 |
51 | b.HasKey("Id");
52 |
53 | b.HasIndex("CategoryId");
54 |
55 | b.ToTable("Product");
56 |
57 | b.HasData(
58 | new
59 | {
60 | Id = new Guid("bc4987fe-1226-419c-b140-cf6327542b32"),
61 | CategoryId = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
62 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
63 | Description = "HP Zbook Laptop",
64 | Price = 2000m,
65 | ProductName = "HP Zbook",
66 | Weight = 3.0
67 | },
68 | new
69 | {
70 | Id = new Guid("0ffd7b32-0df0-40c0-9905-6ad65ae11433"),
71 | CategoryId = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
72 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
73 | Description = "MacBook Laptop",
74 | Price = 3000m,
75 | ProductName = "MacBook Pro",
76 | Weight = 2.1000000000000001
77 | },
78 | new
79 | {
80 | Id = new Guid("baaeab63-7bab-467c-a06f-274eedea528a"),
81 | CategoryId = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
82 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
83 | Description = "Lenovo Thinkpad Laptop",
84 | Price = 2800m,
85 | ProductName = "Lenovo Thinkpad",
86 | Weight = 1.7
87 | },
88 | new
89 | {
90 | Id = new Guid("2f2aed89-f417-4225-822a-113baf3041f5"),
91 | CategoryId = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
92 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
93 | Description = "LG 32-Inch 720p LED TV",
94 | Price = 12000m,
95 | ProductName = "LG 32-Inch",
96 | Weight = 60.0
97 | },
98 | new
99 | {
100 | Id = new Guid("570b67c6-7a24-4041-8582-0ceba4debf0b"),
101 | CategoryId = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
102 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
103 | Description = "Sony 65-Inch 4K Ultra HD Smart LED TV",
104 | Price = 10000m,
105 | ProductName = "Sony 65-Inch",
106 | Weight = 70.0
107 | },
108 | new
109 | {
110 | Id = new Guid("5d54be88-12fa-4ccf-b394-c8d909111449"),
111 | CategoryId = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
112 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
113 | Description = "Samsung 32-Inch 1080p Smart LED TV",
114 | Price = 15000m,
115 | ProductName = "Samsung 32-Inch",
116 | Weight = 50.0
117 | },
118 | new
119 | {
120 | Id = new Guid("746e00e0-49dc-42a8-b935-96697f772478"),
121 | CategoryId = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
122 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
123 | Description = "JBL Tune 500BT On-Ear",
124 | Price = 15m,
125 | ProductName = "JBL Tune",
126 | Weight = 0.29999999999999999
127 | },
128 | new
129 | {
130 | Id = new Guid("218a34f5-52a0-4106-9c98-ba3acdf3db6f"),
131 | CategoryId = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
132 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
133 | Description = "Panasonic ErgoFit In-Ear",
134 | Price = 29m,
135 | ProductName = "Panasonic ErgoFit",
136 | Weight = 0.40000000000000002
137 | },
138 | new
139 | {
140 | Id = new Guid("390ab7d0-3d23-456b-854c-0e5b153b08fa"),
141 | CategoryId = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
142 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
143 | Description = "Sennheiser CX Wireless In-Ear",
144 | Price = 44m,
145 | ProductName = "Sennheiser CX",
146 | Weight = 0.40000000000000002
147 | });
148 | });
149 |
150 | modelBuilder.Entity("OData.WebApi.Data.Entities.ProductCategory", b =>
151 | {
152 | b.Property("Id")
153 | .ValueGeneratedOnAdd();
154 |
155 | b.Property("CategoryName");
156 |
157 | b.Property("CreatedBy")
158 | .ValueGeneratedOnAdd()
159 | .HasDefaultValue("skose");
160 |
161 | b.Property("CreatedDate")
162 | .ValueGeneratedOnAdd()
163 | .HasDefaultValue(new DateTime(2019, 10, 30, 22, 58, 59, 253, DateTimeKind.Local).AddTicks(537));
164 |
165 | b.Property("UpdatedBy");
166 |
167 | b.Property("UpdatedDate");
168 |
169 | b.HasKey("Id");
170 |
171 | b.ToTable("ProductCategory");
172 |
173 | b.HasData(
174 | new
175 | {
176 | Id = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
177 | CategoryName = "TV",
178 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
179 | },
180 | new
181 | {
182 | Id = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
183 | CategoryName = "Headphones",
184 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
185 | },
186 | new
187 | {
188 | Id = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
189 | CategoryName = "Computers",
190 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
191 | });
192 | });
193 |
194 | modelBuilder.Entity("OData.WebApi.Data.Entities.Product", b =>
195 | {
196 | b.HasOne("OData.WebApi.Data.Entities.ProductCategory", "Category")
197 | .WithMany()
198 | .HasForeignKey("CategoryId")
199 | .OnDelete(DeleteBehavior.Cascade);
200 | });
201 | #pragma warning restore 612, 618
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Migrations/20191030195859_init.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore.Migrations;
3 |
4 | namespace OData.WebApi.Data.Migrations
5 | {
6 | public partial class init : Migration
7 | {
8 | protected override void Up(MigrationBuilder migrationBuilder)
9 | {
10 | migrationBuilder.CreateTable(
11 | name: "ProductCategory",
12 | columns: table => new
13 | {
14 | Id = table.Column(nullable: false),
15 | CreatedDate = table.Column(nullable: false, defaultValue: new DateTime(2019, 10, 30, 22, 58, 59, 253, DateTimeKind.Local).AddTicks(537)),
16 | CreatedBy = table.Column(nullable: true, defaultValue: "skose"),
17 | UpdatedDate = table.Column(nullable: true),
18 | UpdatedBy = table.Column(nullable: true),
19 | CategoryName = table.Column(nullable: true)
20 | },
21 | constraints: table =>
22 | {
23 | table.PrimaryKey("PK_ProductCategory", x => x.Id);
24 | });
25 |
26 | migrationBuilder.CreateTable(
27 | name: "Product",
28 | columns: table => new
29 | {
30 | Id = table.Column(nullable: false),
31 | CreatedDate = table.Column(nullable: false, defaultValue: new DateTime(2019, 10, 30, 22, 58, 59, 249, DateTimeKind.Local).AddTicks(675)),
32 | CreatedBy = table.Column(nullable: true, defaultValue: "skose"),
33 | UpdatedDate = table.Column(nullable: true),
34 | UpdatedBy = table.Column(nullable: true),
35 | ProductName = table.Column(nullable: true),
36 | CategoryId = table.Column(nullable: false),
37 | Description = table.Column(nullable: true),
38 | Price = table.Column(nullable: false),
39 | Weight = table.Column(nullable: false)
40 | },
41 | constraints: table =>
42 | {
43 | table.PrimaryKey("PK_Product", x => x.Id);
44 | table.ForeignKey(
45 | name: "FK_Product_ProductCategory_CategoryId",
46 | column: x => x.CategoryId,
47 | principalTable: "ProductCategory",
48 | principalColumn: "Id",
49 | onDelete: ReferentialAction.Cascade);
50 | });
51 |
52 | migrationBuilder.InsertData(
53 | table: "ProductCategory",
54 | columns: new[] { "Id", "CategoryName", "UpdatedBy", "UpdatedDate" },
55 | values: new object[] { new Guid("8b726886-e719-413c-a125-939ee5af387d"), "TV", null, null });
56 |
57 | migrationBuilder.InsertData(
58 | table: "ProductCategory",
59 | columns: new[] { "Id", "CategoryName", "UpdatedBy", "UpdatedDate" },
60 | values: new object[] { new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"), "Headphones", null, null });
61 |
62 | migrationBuilder.InsertData(
63 | table: "ProductCategory",
64 | columns: new[] { "Id", "CategoryName", "UpdatedBy", "UpdatedDate" },
65 | values: new object[] { new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"), "Computers", null, null });
66 |
67 | migrationBuilder.InsertData(
68 | table: "Product",
69 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
70 | values: new object[] { new Guid("2f2aed89-f417-4225-822a-113baf3041f5"), new Guid("8b726886-e719-413c-a125-939ee5af387d"), "LG 32-Inch 720p LED TV", 12000m, "LG 32-Inch", null, null, 60.0 });
71 |
72 | migrationBuilder.InsertData(
73 | table: "Product",
74 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
75 | values: new object[] { new Guid("570b67c6-7a24-4041-8582-0ceba4debf0b"), new Guid("8b726886-e719-413c-a125-939ee5af387d"), "Sony 65-Inch 4K Ultra HD Smart LED TV", 10000m, "Sony 65-Inch", null, null, 70.0 });
76 |
77 | migrationBuilder.InsertData(
78 | table: "Product",
79 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
80 | values: new object[] { new Guid("5d54be88-12fa-4ccf-b394-c8d909111449"), new Guid("8b726886-e719-413c-a125-939ee5af387d"), "Samsung 32-Inch 1080p Smart LED TV", 15000m, "Samsung 32-Inch", null, null, 50.0 });
81 |
82 | migrationBuilder.InsertData(
83 | table: "Product",
84 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
85 | values: new object[] { new Guid("746e00e0-49dc-42a8-b935-96697f772478"), new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"), "JBL Tune 500BT On-Ear", 15m, "JBL Tune", null, null, 0.29999999999999999 });
86 |
87 | migrationBuilder.InsertData(
88 | table: "Product",
89 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
90 | values: new object[] { new Guid("218a34f5-52a0-4106-9c98-ba3acdf3db6f"), new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"), "Panasonic ErgoFit In-Ear", 29m, "Panasonic ErgoFit", null, null, 0.40000000000000002 });
91 |
92 | migrationBuilder.InsertData(
93 | table: "Product",
94 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
95 | values: new object[] { new Guid("390ab7d0-3d23-456b-854c-0e5b153b08fa"), new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"), "Sennheiser CX Wireless In-Ear", 44m, "Sennheiser CX", null, null, 0.40000000000000002 });
96 |
97 | migrationBuilder.InsertData(
98 | table: "Product",
99 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
100 | values: new object[] { new Guid("bc4987fe-1226-419c-b140-cf6327542b32"), new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"), "HP Zbook Laptop", 2000m, "HP Zbook", null, null, 3.0 });
101 |
102 | migrationBuilder.InsertData(
103 | table: "Product",
104 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
105 | values: new object[] { new Guid("0ffd7b32-0df0-40c0-9905-6ad65ae11433"), new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"), "MacBook Laptop", 3000m, "MacBook Pro", null, null, 2.1000000000000001 });
106 |
107 | migrationBuilder.InsertData(
108 | table: "Product",
109 | columns: new[] { "Id", "CategoryId", "Description", "Price", "ProductName", "UpdatedBy", "UpdatedDate", "Weight" },
110 | values: new object[] { new Guid("baaeab63-7bab-467c-a06f-274eedea528a"), new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"), "Lenovo Thinkpad Laptop", 2800m, "Lenovo Thinkpad", null, null, 1.7 });
111 |
112 | migrationBuilder.CreateIndex(
113 | name: "IX_Product_CategoryId",
114 | table: "Product",
115 | column: "CategoryId");
116 | }
117 |
118 | protected override void Down(MigrationBuilder migrationBuilder)
119 | {
120 | migrationBuilder.DropTable(
121 | name: "Product");
122 |
123 | migrationBuilder.DropTable(
124 | name: "ProductCategory");
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Migrations/ProductDbContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
6 | using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
7 | using OData.WebApi.Data;
8 |
9 | namespace OData.WebApi.Data.Migrations
10 | {
11 | [DbContext(typeof(ProductDbContext))]
12 | partial class ProductDbContextModelSnapshot : ModelSnapshot
13 | {
14 | protected override void BuildModel(ModelBuilder modelBuilder)
15 | {
16 | #pragma warning disable 612, 618
17 | modelBuilder
18 | .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
19 | .HasAnnotation("ProductVersion", "2.2.4-servicing-10062")
20 | .HasAnnotation("Relational:MaxIdentifierLength", 63);
21 |
22 | modelBuilder.Entity("OData.WebApi.Data.Entities.Product", b =>
23 | {
24 | b.Property("Id")
25 | .ValueGeneratedOnAdd();
26 |
27 | b.Property("CategoryId");
28 |
29 | b.Property("CreatedBy")
30 | .ValueGeneratedOnAdd()
31 | .HasDefaultValue("skose");
32 |
33 | b.Property("CreatedDate")
34 | .ValueGeneratedOnAdd()
35 | .HasDefaultValue(new DateTime(2019, 10, 30, 22, 58, 59, 249, DateTimeKind.Local).AddTicks(675));
36 |
37 | b.Property("Description");
38 |
39 | b.Property("Price");
40 |
41 | b.Property("ProductName");
42 |
43 | b.Property("UpdatedBy");
44 |
45 | b.Property("UpdatedDate");
46 |
47 | b.Property("Weight");
48 |
49 | b.HasKey("Id");
50 |
51 | b.HasIndex("CategoryId");
52 |
53 | b.ToTable("Product");
54 |
55 | b.HasData(
56 | new
57 | {
58 | Id = new Guid("bc4987fe-1226-419c-b140-cf6327542b32"),
59 | CategoryId = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
60 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
61 | Description = "HP Zbook Laptop",
62 | Price = 2000m,
63 | ProductName = "HP Zbook",
64 | Weight = 3.0
65 | },
66 | new
67 | {
68 | Id = new Guid("0ffd7b32-0df0-40c0-9905-6ad65ae11433"),
69 | CategoryId = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
70 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
71 | Description = "MacBook Laptop",
72 | Price = 3000m,
73 | ProductName = "MacBook Pro",
74 | Weight = 2.1000000000000001
75 | },
76 | new
77 | {
78 | Id = new Guid("baaeab63-7bab-467c-a06f-274eedea528a"),
79 | CategoryId = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
80 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
81 | Description = "Lenovo Thinkpad Laptop",
82 | Price = 2800m,
83 | ProductName = "Lenovo Thinkpad",
84 | Weight = 1.7
85 | },
86 | new
87 | {
88 | Id = new Guid("2f2aed89-f417-4225-822a-113baf3041f5"),
89 | CategoryId = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
90 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
91 | Description = "LG 32-Inch 720p LED TV",
92 | Price = 12000m,
93 | ProductName = "LG 32-Inch",
94 | Weight = 60.0
95 | },
96 | new
97 | {
98 | Id = new Guid("570b67c6-7a24-4041-8582-0ceba4debf0b"),
99 | CategoryId = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
100 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
101 | Description = "Sony 65-Inch 4K Ultra HD Smart LED TV",
102 | Price = 10000m,
103 | ProductName = "Sony 65-Inch",
104 | Weight = 70.0
105 | },
106 | new
107 | {
108 | Id = new Guid("5d54be88-12fa-4ccf-b394-c8d909111449"),
109 | CategoryId = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
110 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
111 | Description = "Samsung 32-Inch 1080p Smart LED TV",
112 | Price = 15000m,
113 | ProductName = "Samsung 32-Inch",
114 | Weight = 50.0
115 | },
116 | new
117 | {
118 | Id = new Guid("746e00e0-49dc-42a8-b935-96697f772478"),
119 | CategoryId = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
120 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
121 | Description = "JBL Tune 500BT On-Ear",
122 | Price = 15m,
123 | ProductName = "JBL Tune",
124 | Weight = 0.29999999999999999
125 | },
126 | new
127 | {
128 | Id = new Guid("218a34f5-52a0-4106-9c98-ba3acdf3db6f"),
129 | CategoryId = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
130 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
131 | Description = "Panasonic ErgoFit In-Ear",
132 | Price = 29m,
133 | ProductName = "Panasonic ErgoFit",
134 | Weight = 0.40000000000000002
135 | },
136 | new
137 | {
138 | Id = new Guid("390ab7d0-3d23-456b-854c-0e5b153b08fa"),
139 | CategoryId = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
140 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
141 | Description = "Sennheiser CX Wireless In-Ear",
142 | Price = 44m,
143 | ProductName = "Sennheiser CX",
144 | Weight = 0.40000000000000002
145 | });
146 | });
147 |
148 | modelBuilder.Entity("OData.WebApi.Data.Entities.ProductCategory", b =>
149 | {
150 | b.Property("Id")
151 | .ValueGeneratedOnAdd();
152 |
153 | b.Property("CategoryName");
154 |
155 | b.Property("CreatedBy")
156 | .ValueGeneratedOnAdd()
157 | .HasDefaultValue("skose");
158 |
159 | b.Property("CreatedDate")
160 | .ValueGeneratedOnAdd()
161 | .HasDefaultValue(new DateTime(2019, 10, 30, 22, 58, 59, 253, DateTimeKind.Local).AddTicks(537));
162 |
163 | b.Property("UpdatedBy");
164 |
165 | b.Property("UpdatedDate");
166 |
167 | b.HasKey("Id");
168 |
169 | b.ToTable("ProductCategory");
170 |
171 | b.HasData(
172 | new
173 | {
174 | Id = new Guid("8b726886-e719-413c-a125-939ee5af387d"),
175 | CategoryName = "TV",
176 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
177 | },
178 | new
179 | {
180 | Id = new Guid("1236a458-0802-4340-bdd4-05859c9aaaad"),
181 | CategoryName = "Headphones",
182 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
183 | },
184 | new
185 | {
186 | Id = new Guid("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
187 | CategoryName = "Computers",
188 | CreatedDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
189 | });
190 | });
191 |
192 | modelBuilder.Entity("OData.WebApi.Data.Entities.Product", b =>
193 | {
194 | b.HasOne("OData.WebApi.Data.Entities.ProductCategory", "Category")
195 | .WithMany()
196 | .HasForeignKey("CategoryId")
197 | .OnDelete(DeleteBehavior.Cascade);
198 | });
199 | #pragma warning restore 612, 618
200 | }
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/ProductDbContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using OData.WebApi.Data.TypeConfigurations;
3 |
4 | namespace OData.WebApi.Data
5 | {
6 | public class ProductDbContext : DbContext
7 | {
8 | public ProductDbContext(DbContextOptions dbOptions)
9 | : base(dbOptions)
10 | {
11 |
12 | }
13 |
14 | protected override void OnModelCreating(ModelBuilder builder)
15 | {
16 | builder.ApplyConfiguration(new ProductTypeConfiguration());
17 | builder.ApplyConfiguration(new ProductCategoryTypeConfiguration());
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Repositories/IRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using OData.WebApi.Data.Entities;
6 |
7 | namespace OData.WebApi.Data.Repositories
8 | {
9 | public interface IRepository
10 | where TEntity : BaseEntity
11 | {
12 | Task IsExistAsync(Guid id);
13 | void Add(TEntity obj);
14 | void Update(TEntity obj);
15 | void Delete(object id);
16 | Task SaveChangesAsync();
17 | IQueryable Query();
18 | }
19 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/Repositories/Repository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using OData.WebApi.Data.Entities;
7 |
8 | namespace OData.WebApi.Data.Repositories
9 | {
10 | public class Repository : IRepository
11 | where TEntity : BaseEntity
12 | {
13 | private ProductDbContext _context;
14 | private DbSet _dbSet;
15 | public Repository(ProductDbContext context)
16 | {
17 | _context = context;
18 | _dbSet = _context.Set();
19 | }
20 |
21 | public async Task IsExistAsync(Guid id)
22 | {
23 | return await _dbSet.AsNoTracking().FirstOrDefaultAsync(q => q.Id == id) != null;
24 | }
25 | public void Add(TEntity entity)
26 | {
27 | entity.CreatedDate = DateTime.Now;
28 | entity.CreatedBy = "admin";
29 | _dbSet.Add(entity);
30 | }
31 | public void Update(TEntity entity)
32 | {
33 | entity.UpdatedDate = DateTime.Now;
34 | entity.UpdatedBy = "admin";
35 | _dbSet.Attach(entity);
36 | _context.Entry(entity).State = EntityState.Modified;
37 | }
38 | public void Delete(object id)
39 | {
40 | TEntity existing = _dbSet.Find(id);
41 | _dbSet.Remove(existing);
42 | }
43 | public Task SaveChangesAsync()
44 | {
45 | return _context.SaveChangesAsync();
46 | }
47 |
48 | public IQueryable Query()
49 | {
50 | return _dbSet;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/TypeConfigurations/ProductCategoryTypeConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
4 | using OData.WebApi.Data.Entities;
5 |
6 | namespace OData.WebApi.Data.TypeConfigurations
7 | {
8 | public class ProductCategoryTypeConfiguration : IEntityTypeConfiguration
9 | {
10 | public void Configure(EntityTypeBuilder builder)
11 | {
12 | builder.Property(s => s.CreatedDate).HasDefaultValue(DateTime.Now);
13 | builder.Property(s => s.CreatedBy).HasDefaultValue("skose");
14 |
15 | builder.HasData(
16 | new ProductCategory
17 | {
18 | Id = Guid.Parse("8b726886-e719-413c-a125-939ee5af387d"),
19 | CategoryName = "TV"
20 | },
21 | new ProductCategory
22 | {
23 | Id = Guid.Parse("1236a458-0802-4340-bdd4-05859c9aaaad"),
24 | CategoryName = "Headphones"
25 | },
26 | new ProductCategory
27 | {
28 | Id = Guid.Parse("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
29 | CategoryName = "Computers"
30 | });
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Data/TypeConfigurations/ProductTypeConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore;
3 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
4 | using OData.WebApi.Data.Entities;
5 |
6 | namespace OData.WebApi.Data.TypeConfigurations
7 | {
8 | public class ProductTypeConfiguration : IEntityTypeConfiguration
9 | {
10 | public void Configure(EntityTypeBuilder builder)
11 | {
12 | builder.Property(s => s.CreatedDate).HasDefaultValue(DateTime.Now);
13 | builder.Property(s => s.CreatedBy).HasDefaultValue("skose");
14 |
15 | builder.HasData(
16 |
17 | //Computer Products
18 | new Product
19 | {
20 | Id = Guid.NewGuid(),
21 | CategoryId = Guid.Parse("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
22 | ProductName = "HP Zbook",
23 | Description = "HP Zbook Laptop",
24 | Weight = 3,
25 | Price = 2000
26 | },
27 | new Product
28 | {
29 | Id = Guid.NewGuid(),
30 | CategoryId = Guid.Parse("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
31 | ProductName = "MacBook Pro",
32 | Description = "MacBook Laptop",
33 | Weight = 2.1,
34 | Price = 3000
35 | },
36 | new Product
37 | {
38 | Id = Guid.NewGuid(),
39 | CategoryId = Guid.Parse("a65bc1ae-c1c7-4c20-8b3b-4b48490d3fb0"),
40 | ProductName = "Lenovo Thinkpad",
41 | Description = "Lenovo Thinkpad Laptop",
42 | Weight = 1.7,
43 | Price = 2800
44 | },
45 |
46 | //TV Products
47 | new Product
48 | {
49 | Id = Guid.NewGuid(),
50 | CategoryId = Guid.Parse("8b726886-e719-413c-a125-939ee5af387d"),
51 | ProductName = "LG 32-Inch",
52 | Description = "LG 32-Inch 720p LED TV",
53 | Weight = 60,
54 | Price = 12000
55 | },
56 | new Product
57 | {
58 | Id = Guid.NewGuid(),
59 | CategoryId = Guid.Parse("8b726886-e719-413c-a125-939ee5af387d"),
60 | ProductName = "Sony 65-Inch",
61 | Description = "Sony 65-Inch 4K Ultra HD Smart LED TV",
62 | Weight = 70,
63 | Price = 10000
64 | },
65 | new Product
66 | {
67 | Id = Guid.NewGuid(),
68 | CategoryId = Guid.Parse("8b726886-e719-413c-a125-939ee5af387d"),
69 | ProductName = "Samsung 32-Inch",
70 | Description = "Samsung 32-Inch 1080p Smart LED TV",
71 | Weight = 50,
72 | Price = 15000
73 | },
74 |
75 | //Headphone Products
76 | new Product
77 | {
78 | Id = Guid.NewGuid(),
79 | CategoryId = Guid.Parse("1236a458-0802-4340-bdd4-05859c9aaaad"),
80 | ProductName = "JBL Tune",
81 | Description = "JBL Tune 500BT On-Ear",
82 | Weight = 0.3,
83 | Price = 15
84 | },
85 | new Product
86 | {
87 | Id = Guid.NewGuid(),
88 | CategoryId = Guid.Parse("1236a458-0802-4340-bdd4-05859c9aaaad"),
89 | ProductName = "Panasonic ErgoFit",
90 | Description = "Panasonic ErgoFit In-Ear",
91 | Weight = 0.4,
92 | Price = 29
93 | },
94 | new Product
95 | {
96 | Id = Guid.NewGuid(),
97 | CategoryId = Guid.Parse("1236a458-0802-4340-bdd4-05859c9aaaad"),
98 | ProductName = "Sennheiser CX",
99 | Description = "Sennheiser CX Wireless In-Ear",
100 | Weight = 0.4,
101 | Price = 44
102 | });
103 | }
104 | }
105 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Dto/ProductCategoryDto.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OData.WebApi.Dto
4 | {
5 | public class ProductCategoryDto
6 | {
7 | public Guid Id { get; set; }
8 | public string CategoryName { get; set; }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Dto/ProductDto.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using OData.WebApi.Data.Entities;
3 |
4 | namespace OData.WebApi.Dto
5 | {
6 | public class ProductDto
7 | {
8 | public Guid Id { get; set; }
9 | public string ProductName { get; set; }
10 | public Guid CategoryId { get; set; }
11 | public string Description { get; set; }
12 | public decimal Price { get; set; }
13 | public double Weight { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/OData.WebApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 | InProcess
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/OData.WebApi/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore;
2 | using Microsoft.AspNetCore.Hosting;
3 |
4 | namespace OData.WebApi
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateWebHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
14 | WebHost.CreateDefaultBuilder(args)
15 | .UseStartup();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/OData.WebApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:15577",
8 | "sslPort": 44330
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "api/values",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "OData.WebApi": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "api/values",
24 | "applicationUrl": "http://localhost:5000",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/OData.WebApi/Startup.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Microsoft.AspNet.OData.Builder;
3 | using Microsoft.AspNet.OData.Extensions;
4 | using Microsoft.AspNet.OData.Formatter;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.EntityFrameworkCore;
9 | using Microsoft.Extensions.Configuration;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Net.Http.Headers;
12 | using Microsoft.OData.Edm;
13 | using OData.WebApi.Data;
14 | using OData.WebApi.Data.Entities;
15 | using OData.WebApi.Data.Repositories;
16 | using OData.WebApi.Dto;
17 |
18 | namespace OData.WebApi
19 | {
20 | public class Startup
21 | {
22 | public Startup(IConfiguration configuration)
23 | {
24 | Configuration = configuration;
25 | }
26 |
27 | public IConfiguration Configuration { get; }
28 |
29 | public void ConfigureServices(IServiceCollection services)
30 | {
31 | services.AddDbContext(
32 | options => options.UseNpgsql(Configuration.GetConnectionString("ProductConStr")));
33 | services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
34 |
35 | services
36 | .AddMvc(options => options.EnableEndpointRouting = false)
37 | .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
38 | services.AddOData();
39 | }
40 |
41 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
42 | {
43 | using (var serviceScope = app.ApplicationServices.GetRequiredService().CreateScope())
44 | {
45 | using (var context = serviceScope.ServiceProvider.GetService())
46 | {
47 | context.Database.Migrate();
48 | }
49 | }
50 |
51 | app.UseMvc(
52 | routeBuilder =>
53 | {
54 | // routeBuilder.EnableDependencyInjection(); //Enables the non-OData route container.
55 | // routeBuilder.Filter().Count().Expand().OrderBy().Select();
56 | routeBuilder.MapODataServiceRoute("ODataRoute", "odata", GetEdmModel());
57 | });
58 | }
59 |
60 | private static IEdmModel GetEdmModel()
61 | {
62 | var builder = new ODataConventionModelBuilder();
63 | builder.EnableLowerCamelCase();
64 |
65 | builder.EntitySet("products")
66 | .EntityType.Filter().Count().Expand().OrderBy().Page().Select();
67 |
68 | builder.EntitySet("product_categories")
69 | .EntityType.Filter().Count().Expand().OrderBy().Page().Select();
70 |
71 | return builder.GetEdmModel();
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/OData.WebApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "ProductConStr": "Host=localhost;Port=5436;Username=postgres;Password=postgres;Database=OData;"
4 | },
5 | "Logging": {
6 | "LogLevel": {
7 | "Default": "Debug"
8 | }
9 | },
10 | "AllowedHosts": "*"
11 | }
--------------------------------------------------------------------------------