C# EF code first Backend API test project
In my life I have write millions string of .NET code, of course most of that code I made on VB.NET, because this is my liked language. And I used any existing .NET features in my VB.NET program, for example:
- 1. Pass ByVal/ByRef param, Override/virtual method, Encapsulation public/private/protected
- VB: Inheritance, Event, Extension, listener How to intercept exception & console output & debug trace and show it in textbox.
- VB: Overrides Customize Newtonsoft.Json Serializer/Deserializer to convert Javascript Datetime and Number to .NET datatype.
- VB: Generic VB.NET function for loading ExcelFile to DataBase (EF6 CodeFirst) with Reflection and avoiding Linq-to-Entity Linq.Expressions (use Linq-to-Object IEnumerable)
- VB: Generic Five amazing Linq-to-SQL extensio
- VB: Як будуються адаптивні сайти для мобільників та десктопів на CLASSIC ASP.NET
- 2. String/string, cryptography
- VB: Encrypt sensitive data in DB by Rijndael symmetric algorithm.
- VB: Linux shell parser (Renci.SshNet.SshClient, MySqlConnector.NET, RSA encription, Console password, XDocument/XPath, Tuple, Regex, Buffer.BlockCopy, Stream, Base64String, UTF8.GetBytes, ToString("X2"))
- 3. Tuples and other collection, generic and non-generic
- 4. Events and delegates, recursion, param, generic param, Lambda, Extension, Anonimous, (MS DOC Delegates and Events (VB.NET))
- VB: Events vs delegates
- VB: Events/Delegates in VB.NET (Static/Dynamic declaration, AddressOf/RaiseEvent/AddHandler/WithEvents/Handles statement,SingleCast/MultiCast/InvocationList, Invoke/BeginInvoke/DynamicInvoke/AsyncInvoke, Automatically instantiate.
- VB: Оновлення StatusLabel з потоку BackGroundWorker - приклад застосування Action, Delegate, Invoke, AddressOf, Extension, Expression.
- VB: Set HandCursor for all ToolStripButton by Linq, Extension, Delegates, Lambda Expression and Anonymous Action.
- VB: How to reorder DataRow with Extension function, Anonymous types, Lambda Expression and Linq Special Row Comparer.
- VB: How to create Razor html-helper in VB.NET
- VB: Делегаты сравнения для сортировки и Linq-отборов в VB.NET
- VB: Практическое применение наследования, полиморфизма, интерфейсов, дженериков и делегатов на примерах в Visual Basic .NET
- VB: JsonPath more examples.
- 5. Multithreading, LINQ, Nullable
- VB: My multithreading experience.
- Multithreading learning conspectus 2
- VB: Asynchronous MultiThreaded performance test of Confluent Kafka (Net Core 6).
- VB: EventLogger - example of Task.Factory.FromAsync, Task.Run, ReaderWriterLock, Interlocked.Increment, Stream.BeginWrite, SyncLock, Timeout, AsyncCallback, IAsyncResult, String.Format, Timespan.
- VB: Змінні Nullable та як обробляти DBNull з бази за допомогою Extension-функції.
- VB: CheckDBNull, RawSqlQuery, ExecRDR, RawSqlQueryAsync, ExecNonQueryAsync (with transaction)- amazing extension for working with data.
- 6. Yield and IEnumerator , Jagged array, Destructor, Dynamic
- VB: Asynchronous MultiThreaded SSH engine for Web (Net Core 6, Linux) - Part 3,4 (CryptoAPI/CryptoService and Database Access). Protect password in DB and config, Task.Run for Async DB access, Expand POCO classes, Service lifetime list, Linq and Iterator/Yield functions.
- VB: Yeld - TreeView FileSelector by ReactiveNET and TheArtOfDev.HtmlRenderer (SpellChecker project).
- VB: My TDD Technique for Backend API development with Xunit (Custom Attribute, WebClient GET/POST, JWT auth, Fact, Theory, InlineData, ClassData iterator function, Inject Log, Txt parsers for console output)
- VB: SQLServerTxtDump -Example of System.Data.SqlClient, GetSchemaTable, DataTable/DataRow, Action/Func, Linq, Tuple, IEnumerable, Iterator, Yield, Byte.ToString("x2"), DBNull, Array of Object.
- VB: Yield/Iterator/IEnumerable - і ці люди забороняли нам багато років колупатися у носі?
- VB: Serialize Table to CSV with Iterator and Yeld
- VB: Dispose unmanaged resources (configuration, fonts). GC.SuppressFinalize
- VB: Amazing extension function CopyLinqDataMembersByName to expand Linq-to-SQL.
- VB: Generic VB.NET function for loading ExcelFile to DataBase (EF6 CodeFirst) with Reflection and avoiding Linq-to-Entity Linq.Expressions (use Linq-to-Object IEnumerable)
- VB: Collection.Generic.List (of T), IQueryable vs IEnumerable.
- 7. Attributes, Reflection
- VB: Типовий SOAP/WSDL сервіс.
- VB: Складська прога на WCF-сервісах зі сканером.
- VB: My TDD Technique for Backend API development with Xunit (Custom Attribute, WebClient GET/POST, JWT auth, Fact, Theory, InlineData, ClassData iterator function, Inject Log, Txt parsers for console output)
- VB: Customize Newtonsoft.Json Serializer/Deserializer to convert Javascript Datetime and Number to .NET datatype.
- VB: Reflection Object dumper.
- 8. And millions other special .NET technologies (MS DOC Widening and Narrowing Conversions (Visual Basic)):
- VB: BachgroundWorker, Extension RichTextBox Editor for various purposes with row numbering and searching.
- VB: Робота з байтами у VB.NET - ChrW, BitConverter.ToInt32, Convert.ToInt32, Byte.Parse, ToString("X2") / AllowHexSpecifier, GetBytes/GetString, New Byte(N) {}, UInt32 = &H33
- VB: DragAndDrop DataGridView Rows
- VB: EF Code First, Enum FinancialBroker - MDI application with EF code first database.
- VB: Drawing ListView-TabControl-CustomDrawing/index.htm
- VB: Trap unhandled exception in windows application.
However, I made a number of projects exactly on C#, for example:
- ASP.NET Core BackEnd with MailKit/IMAP (Async/Await, Monitor, ConcurrentQueue, CancellationTokenSource)
- AuctionClient site future
- KWMC - description the features of a typical ASP.NET MVC project.
About EF code first technologies, I don't very like this library, because :
- there are a lot of alternative way to access date, all data access method I list in page Classification data access methods.
- EF don't working properly with all existing SQL server, database first (this is 99% of all projects, when data is exist) working fine only with MsSQL, Microsoft ignore any other SQL server and said "this is your responsibility to create providers MySQL. SQLite, PostgeSQL and other SQL". Therefore EF looks as no more than attempt to increase sale of MS SQL server, no more. Stupid and fucking Microsoft attempt to bind MS SQL to .NET code and .NET Framework.
- And common idea of EF looks idiotic - SQL server not a place to store table, who push this stupid idea to Microsoft, each SQL server has hundreds of special opportunity different from stored tables, for example Microsoft SQL server has more than 100 special features additional to stored tables, look for example to first list in this my page SQL servers
- Working with EF code first a lot of difficulties than working simple raw SQL query in that style CheckDBNull, RawSqlQuery, ExecRDR, RawSqlQueryAsync, ExecNonQueryAsync (with transaction)- amazing extension for working with data. Additionally EF entering absolutely new features to working with data like lazy/eager loading
SO, what I want to said? If I prefer more advanced RAPID language for programming, and if I prefer more advanced data access method, if I have strong understanding of Microsoft final goal to bind .NET and MS SQL with EF - this is not mean that I can not be stupid and this not mean than I can not use more stupid and restricted technology. And in that example I demonstrate how I can be stupid and can looks as full newbie and how I can working with goal to increase sales for MS SQL server:
- 2015: FinancialBroker - MDI application with EF code first database.
- 2018: How to use SQLite with EF6.
- 2018: Project for refactoring ODBC access to MySQL up to EF6 Code First with MySQL.
- 2018: Template to save SQLiteDB (EF6) to Temporary Location (automatically and user selected).
- 2019: Generic VB.NET function for loading ExcelFile to DataBase (EF6 CodeFirst) with Reflection and avoiding Linq-to-Entity Linq.Expressions (use Linq-to-Object IEnumerable)
- 2019: My typical VB.NET desktop application.
- 2020: Transform Database from MsSQL to MySQL (Net Core EF DbFirst, Scaffold-DbContext, Read Db Schema, Move Users and data, EF SQL trace)
- 2021: Linux console app (.NET Core, EF DB first, CamelCase file and dir rename, calc MD5, RegExpression, change and check link).
- 2022: BackendAPI (Net Core 5) project template with Custom Attribute, Service and Controller Example, MySQL database with masked password in config, SwaggerUI, EF Core and extension to EF Core
- 2022: About connection with EF Core and Pomelo provider for MySQL (GetProcessList, EF Core connection count, Setup Max MySQL Connection count. Separate connection for Attributes, Calculate connection for API).
So, in current test project I have this database (see details description how I made this DB - C# EF code first. How to create DB context and deploy DB in Net Core 8):
In EF Code first this is description of this database.
1: using Microsoft.EntityFrameworkCore;
2: using Microsoft.Extensions.Configuration;
3: using System;
4: using System.Collections.Generic;
5: using System.Text;
6: using Microsoft.EntityFrameworkCore;
7: using TT.Lib.Entities;
8: using System.IO;
9: using Microsoft.Extensions.Configuration.Json;
10:
11: namespace TT.Lib
12: {
13: public class TTDbContext : DbContext
14: {
15: string connectionString;
16: public DbSet<Product> Products { get; set; }
17: public DbSet<Property> Properties { get; set; }
18: public DbSet<ProductProperty> ProductProperties { get; set; }
19: public TTDbContext(IConfiguration configuration)
20: {
21: this.connectionString = configuration.GetConnectionString(typeof(TTDbContext).Name);
22: }
23: public TTDbContext()
24: {
25: }
26: public string ConnectionString
27: {
28: get
29: {
30: return this.connectionString;
31: }
32: }
33: protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
34: {
35: bool manual = false;
36: if (manual)
37: {
38: IConfigurationRoot configuration = new ConfigurationBuilder()
39: .SetBasePath(Directory.GetCurrentDirectory())
40: .AddJsonFile("appsettings.json")
41: .Build();
42: var connectionString = "Server=localhost;Initial Catalog=tt;Integrated Security=True;TrustServerCertificate=True;";
43: optionsBuilder.UseSqlServer(connectionString);
44: }
45: else
46: {
47: optionsBuilder.UseSqlServer(this.ConnectionString, sqlOptions => sqlOptions
48: .EnableRetryOnFailure(
49: maxRetryCount: 10,
50: maxRetryDelay: TimeSpan.FromSeconds(30),
51: errorNumbersToAdd: null));
52: }
53: base.OnConfiguring(optionsBuilder);
54: }
55: }
56: }
1: namespace TT.Lib.Entities
2: {
3: public class EntityBase
4: {
5: public const string DefaultSchema = "tt";
6: }
7:
8: public class Base : IId
9: {
10: public int Id { get; set; }
11: }
12:
13: public class BaseName : Base
14: {
15: public string Name { get; set; }
16: }
17:
18: public interface IId
19: {
20: public int Id { get; set; }
21: }
22: }
1: using System.Collections.Generic;
2: namespace TT.Lib.Entities
3: {
4: public class Brand : BaseName, IId
5: {
6: public ICollection<Product> Products { get; set; }
7: }
8: }
1: using System.Collections.Generic;
2: using System.ComponentModel.DataAnnotations;
3: namespace TT.Lib.Entities
4: {
5: public class Product : BaseName, IId
6: {
7: public ICollection<ProductProperty> Properties { get; set; }
8: [MaxLength(63)]
9: public string Key { get; set; }
10: public int BrandId { get; set; }
11: public virtual Brand Brand { get; set; }
12: }
13: }
1: namespace TT.Lib.Entities
2: {
3: public class ProductProperty : Base
4: {
5: public string Value { get; set; }
6: public virtual Product Product { get; set; }
7: public int ProductId { get; set; }
8: public virtual Property Property { get; set; }
9: public int PropertyId { get; set; }
10: }
11: }
1: namespace TT.Lib.Entities
2: {
3: public class Property : BaseName
4: {
5: public int ParentId { get; set; }
6: }
7: }
What main disadvantage of EF CODE first comparing to clear access with SQL query? We need huge code support instead clear SQL query, for example in this test project this was a thousands code lines additionally to DB definitions above. If fact DB access is separate library with thousands of code lines:
Than we need to add this repository as scoped services:
Other possible troubles is deployment, I spend whole working day while finally my attempt to deployment (even to Ms SQL!) was successful:
Potential customer take me data and my goal was a create data from Database to frontend with special form what customer required:
So, this is my solution Solution uploaded to Github.
1: using Microsoft.AspNetCore.Mvc;
2: using Microsoft.Identity.Client;
3: using Newtonsoft.Json;
4: using Newtonsoft.Json.Linq;
5: using System;
6: using System.Collections;
7: using System.Collections.Generic;
8: using System.Diagnostics;
9: using System.Dynamic;
10: using System.Linq;
11: using TT.Lib;
12:
13: namespace TT.Api.Controllers
14: {
15: [Route("[controller]")]
16: [ApiController]
17: public class Export : ControllerBase
18: {
19:
20: private readonly TTDbContext _db;
21:
22: public Export(TTDbContext db)
23: {
24: _db = db;
25: }
26:
27: // GET Codes
28: [HttpGet("/Codes")]
29: public IActionResult Codes(string code)
30: {
31: return new OkObjectResult(_db.Products.Select(x => x.Key).ToList());
32:
33: }
34:
35: // GET /Export/Raw/SM2L
36: [HttpGet("Raw/{code}")]
37: public IActionResult ProductDump(string code)
38: {
39: var prod1 = _db.Products.Where(x => x.Key.Equals(code)).Select(x => new Title(x.Id, x.Name, x.Key, x.BrandId, x.Brand.Name)).ToList();
40:
41: Record3 ret1 = new Record3();
42: ret1.title = prod1.FirstOrDefault();
43: ret1.staticProp = new List<OneStatic>();
44:
45: foreach (var x in prod1)
46: {
47: ret1.staticProp.AddRange(_db.ProductProperties.Where(y => y.ProductId.Equals(x.Id)).Select(z => new OneStatic(z.Id, z.Value, z.PropertyId, new List<OneDynamic>())).ToList());
48:
49: }
50: foreach (OneStatic one in ret1.staticProp)
51: {
52: int startId = one.propertyId;
53: do
54: {
55: var ret2 = GetDynProp(startId);
56: if (ret2.Count == 0)
57: {
58: break;
59: }
60: else
61: {
62: one.dynProp.Add(ret2[0]);
63: startId = ret2[0].ParentId;
64: }
65: } while (true);
66:
67: }
68: return new OkObjectResult(ret1);
69: }
70: private List<OneDynamic> GetDynProp(int startId)
71: {
72: return _db.Properties.Where(x => x.Id.Equals(startId)).Select(x => new OneDynamic(x.Id, x.ParentId, x.Name)).ToList();
73: }
74:
75:
76: // GET ExportRaw/SM2L
77: [HttpGet("{code}")]
78: public IActionResult ReverseTreeAndMergeNodes(string code)
79: {
80: var ret1 =(OkObjectResult)ProductDump(code);
81: var rawTree = (Record3)ret1.Value;
82: var out1 = new JObject();
83: out1.Add(new JProperty("id", rawTree.title.Key));
84: out1.Add(new JProperty("name", rawTree.title.Name));
85: // reversy tree
86: var arr1 = new JArray();
87: foreach (var oneStatic in rawTree.staticProp)
88: {
89: Debug.WriteLine($"val:{oneStatic.value}");
90: Boolean first = true;
91: var save = new JObject();
92:
93: foreach (var oneDyn in oneStatic.dynProp.OrderByDescending(x=> x.id))
94: {
95: Debug.WriteLine($"oneDyn:{oneDyn}");
96: if (first)
97: {
98: var dyn = new JObject();
99: dyn.Add(new JProperty(oneDyn.dynName, oneStatic.value));
100: Debug.WriteLine($"dyn:{dyn}");
101: save = dyn;
102: first = false;
103: }
104: else {
105: var dyn = new JObject();
106: dyn.Add(new JProperty(oneDyn.dynName, save));
107: save = dyn;
108: Debug.WriteLine($"dyn:{dyn}");
109: }
110:
111: }
112: arr1.Add(save);
113: Debug.WriteLine($"sum:{arr1}");
114: }
115: // and merge nodes with the same name
116: var sum1 = new JObject();
117: foreach (var one in arr1)
118: {
119: Debug.WriteLine($"one:{one}");
120: sum1.Merge(one);
121: }
122: out1.Add(new JProperty("prop", sum1));
123: return new OkObjectResult(out1);
124: }
125: }
126: record Title(int Id, string Name, string Key, int BrandId, string BrandName);
127: struct OneStatic
128: {
129: public int ProductProperties_Id;
130: public string value;
131: public int propertyId;
132: public List<OneDynamic> dynProp = new List<OneDynamic>();
133: private int id;
134: private List<OneDynamic> oneDynamics;
135:
136: public OneStatic(int id, string value, int propertyId, List<OneDynamic> oneDynamics) : this()
137: {
138: this.id = id;
139: this.value = value;
140: this.propertyId = propertyId;
141: this.oneDynamics = oneDynamics;
142: }
143: };
144: record OneDynamic(int id, int ParentId, string dynName);
145: struct Record3
146: {
147: public Title title;
148: public List<OneStatic> staticProp;
149: }
150: }
|