Skip to content

Commit e1d2bb4

Browse files
committed
create quickStart
1 parent e6a6cd6 commit e1d2bb4

File tree

3 files changed

+394
-0
lines changed

3 files changed

+394
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<ProjectReference Include="..\..\src\Linq2db.Ydb\src\Linq2db.csproj" />
11+
</ItemGroup>
12+
<ItemGroup>
13+
<PackageReference Include="linq2db" Version="6.0.0-rc.3" />
14+
</ItemGroup>
15+
<ItemGroup>
16+
<PackageReference Include="CommandLineParser" Version="2.8.0"/>
17+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0"/>
18+
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0"/>
19+
<PackageReference Include="Polly" Version="8.4.1" />
20+
</ItemGroup>
21+
</Project>
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
namespace Linq2db.QuickStart;
2+
3+
using Microsoft.Extensions.Logging;
4+
using Polly;
5+
using LinqToDB;
6+
using LinqToDB.Async;
7+
using LinqToDB.Data;
8+
using LinqToDB.Mapping;
9+
10+
internal static class Program
11+
{
12+
public static async Task Main(string[] args)
13+
{
14+
using var factory = LoggerFactory.Create(b => b.AddConsole());
15+
var app = new AppContext(factory.CreateLogger<AppContext>());
16+
await app.Run();
17+
}
18+
}
19+
20+
#region LINQ2DB MODELS
21+
22+
[Table("series")]
23+
public sealed class Series
24+
{
25+
[PrimaryKey, Column("series_id")]
26+
public ulong SeriesId { get; set; }
27+
28+
[Column("title"), NotNull]
29+
public string Title { get; set; } = null!;
30+
31+
[Column("series_info")]
32+
public string? SeriesInfo { get; set; }
33+
34+
[Column("release_date"), DataType(DataType.Date)]
35+
public DateTime ReleaseDate { get; set; }
36+
}
37+
38+
[Table("seasons")]
39+
public sealed class Season
40+
{
41+
[PrimaryKey, Column("series_id")]
42+
public ulong SeriesId { get; set; }
43+
44+
[PrimaryKey, Column("season_id")]
45+
public ulong SeasonId { get; set; }
46+
47+
[Column("title"), NotNull]
48+
public string Title { get; set; } = null!;
49+
50+
[Column("first_aired"), DataType(DataType.Date)]
51+
public DateTime FirstAired { get; set; }
52+
53+
[Column("last_aired"), DataType(DataType.Date)]
54+
public DateTime LastAired { get; set; }
55+
}
56+
57+
[Table("episodes")]
58+
public sealed class Episode
59+
{
60+
[PrimaryKey, Column("series_id")]
61+
public ulong SeriesId { get; set; }
62+
63+
[PrimaryKey, Column("season_id")]
64+
public ulong SeasonId { get; set; }
65+
66+
[PrimaryKey, Column("episode_id")]
67+
public ulong EpisodeId { get; set; }
68+
69+
[Column("title"), NotNull]
70+
public string Title { get; set; } = null!;
71+
72+
[Column("air_date"), DataType(DataType.Date)]
73+
public DateTime AirDate { get; set; }
74+
}
75+
76+
#endregion
77+
78+
#region LINQ2DB DATACONTEXT
79+
80+
internal sealed class MyYdb : DataConnection
81+
{
82+
public MyYdb(string connectionString) : base("YDB", connectionString) { }
83+
public MyYdb(DataOptions options) : base(options) { }
84+
85+
public ITable<Series> Series => this.GetTable<Series>();
86+
public ITable<Season> Seasons => this.GetTable<Season>();
87+
public ITable<Episode> Episodes => this.GetTable<Episode>();
88+
}
89+
90+
#endregion
91+
92+
#region SETTINGS (без CmdOptions)
93+
94+
internal sealed record Settings(
95+
string Host,
96+
int Port,
97+
string Database,
98+
bool UseTls,
99+
int TlsPort)
100+
{
101+
public string SimpleConnectionString =>
102+
$"Host={Host};Port={(UseTls ? TlsPort : Port)};Database={Database};UseTls={(UseTls ? "true" : "false")}";
103+
}
104+
105+
internal static class SettingsLoader
106+
{
107+
public static Settings Load()
108+
{
109+
string host = Environment.GetEnvironmentVariable("YDB_HOST") ?? "localhost";
110+
int port = TryInt(Environment.GetEnvironmentVariable("YDB_PORT"), 2136);
111+
string db = Environment.GetEnvironmentVariable("YDB_DB") ?? "/local";
112+
bool useTls = TryBool(Environment.GetEnvironmentVariable("YDB_USE_TLS"), false);
113+
int tls = TryInt(Environment.GetEnvironmentVariable("YDB_TLS_PORT"), 2135);
114+
115+
return new Settings(host, port, db, useTls, tls);
116+
117+
static int TryInt(string? s, int d) => int.TryParse(s, out var v) ? v : d;
118+
static bool TryBool(string? s, bool d) => bool.TryParse(s, out var v) ? v : d;
119+
}
120+
}
121+
122+
#endregion
123+
124+
internal class AppContext
125+
{
126+
private readonly ILogger<AppContext> _logger;
127+
private readonly Settings _settings;
128+
129+
public AppContext(ILogger<AppContext> logger)
130+
{
131+
_logger = logger;
132+
_settings = SettingsLoader.Load();
133+
}
134+
135+
DataOptions BuildOptions(string? overrideConnectionString = null)
136+
{
137+
var cs = overrideConnectionString ?? _settings.SimpleConnectionString;
138+
return new DataOptions().UseConnectionString("YDB", cs);
139+
}
140+
141+
public async Task Run()
142+
{
143+
_logger.LogInformation("Start app example");
144+
145+
await InitTables();
146+
await LoadData();
147+
await SelectWithParameters();
148+
await RetryPolicy();
149+
150+
151+
await InteractiveTransaction();
152+
await TlsConnectionExample();
153+
await ConnectionWithLoggerFactory();
154+
155+
_logger.LogInformation("Finish app example");
156+
}
157+
158+
private async Task InitTables()
159+
{
160+
await using var db = new MyYdb(BuildOptions());
161+
162+
try { await db.CreateTableAsync<Series>(); } catch { _logger.LogDebug("series exists"); }
163+
try { await db.CreateTableAsync<Season>(); } catch { _logger.LogDebug("seasons exists"); }
164+
try { await db.CreateTableAsync<Episode>(); } catch { _logger.LogDebug("episodes exists"); }
165+
166+
_logger.LogInformation("Created tables");
167+
}
168+
169+
private async Task LoadData()
170+
{
171+
await using var db = new MyYdb(BuildOptions());
172+
173+
var series = new[]
174+
{
175+
new Series { SeriesId = 1, Title = "IT Crowd", ReleaseDate = new DateTime(2006,02,03), SeriesInfo="British sitcom..." },
176+
new Series { SeriesId = 2, Title = "Silicon Valley", ReleaseDate = new DateTime(2014,04,06), SeriesInfo="American comedy..." }
177+
};
178+
foreach (var s in series) await db.InsertAsync(s);
179+
180+
var seasons = new List<Season>
181+
{
182+
new() { SeriesId=1, SeasonId=1, Title="Season 1", FirstAired=new DateTime(2006,02,03), LastAired=new DateTime(2006,03,03)},
183+
new() { SeriesId=1, SeasonId=2, Title="Season 2", FirstAired=new DateTime(2007,08,24), LastAired=new DateTime(2007,09,28)},
184+
new() { SeriesId=1, SeasonId=3, Title="Season 3", FirstAired=new DateTime(2008,11,21), LastAired=new DateTime(2008,12,26)},
185+
new() { SeriesId=1, SeasonId=4, Title="Season 4", FirstAired=new DateTime(2010,06,25), LastAired=new DateTime(2010,07,30)},
186+
new() { SeriesId=2, SeasonId=1, Title="Season 1", FirstAired=new DateTime(2014,04,06), LastAired=new DateTime(2014,06,01)},
187+
new() { SeriesId=2, SeasonId=2, Title="Season 2", FirstAired=new DateTime(2015,04,12), LastAired=new DateTime(2015,06,14)},
188+
new() { SeriesId=2, SeasonId=3, Title="Season 3", FirstAired=new DateTime(2016,04,24), LastAired=new DateTime(2016,06,26)},
189+
new() { SeriesId=2, SeasonId=4, Title="Season 4", FirstAired=new DateTime(2017,04,23), LastAired=new DateTime(2017,06,25)},
190+
new() { SeriesId=2, SeasonId=5, Title="Season 5", FirstAired=new DateTime(2018,03,25), LastAired=new DateTime(2018,05,13)},
191+
};
192+
await db.BulkCopyAsync(seasons);
193+
194+
var eps = new List<Episode>
195+
{
196+
new() { SeriesId=1, SeasonId=1, EpisodeId=1, Title="Yesterday's Jam", AirDate=new DateTime(2006,02,03)},
197+
new() { SeriesId=1, SeasonId=1, EpisodeId=2, Title="Calamity Jen", AirDate=new DateTime(2006,02,03)},
198+
new() { SeriesId=1, SeasonId=1, EpisodeId=3, Title="Fifty-Fifty", AirDate=new DateTime(2006,02,10)},
199+
new() { SeriesId=1, SeasonId=1, EpisodeId=4, Title="The Red Door", AirDate=new DateTime(2006,02,17)},
200+
new() { SeriesId=1, SeasonId=2, EpisodeId=1, Title="The Work Outing", AirDate=new DateTime(2007,08,24)},
201+
new() { SeriesId=1, SeasonId=2, EpisodeId=2, Title="Return of the Golden Child", AirDate=new DateTime(2007,08,31)},
202+
new() { SeriesId=1, SeasonId=3, EpisodeId=1, Title="From Hell", AirDate=new DateTime(2008,11,21)},
203+
new() { SeriesId=1, SeasonId=3, EpisodeId=2, Title="Are We Not Men?", AirDate=new DateTime(2008,11,28)},
204+
new() { SeriesId=1, SeasonId=4, EpisodeId=1, Title="Jen The Fredo", AirDate=new DateTime(2010,06,25)},
205+
new() { SeriesId=1, SeasonId=4, EpisodeId=2, Title="The Final Countdown", AirDate=new DateTime(2010,07,02)},
206+
new() { SeriesId=2, SeasonId=2, EpisodeId=1, Title="Minimum Viable Product", AirDate=new DateTime(2014,04,06)},
207+
new() { SeriesId=2, SeasonId=2, EpisodeId=2, Title="The Cap Table", AirDate=new DateTime(2014,04,13)},
208+
new() { SeriesId=2, SeasonId=1, EpisodeId=3, Title="Articles of Incorporation", AirDate=new DateTime(2014,04,20)},
209+
new() { SeriesId=2, SeasonId=1, EpisodeId=4, Title="Fiduciary Duties", AirDate=new DateTime(2014,04,27)},
210+
};
211+
212+
await db.BulkCopyAsync(eps);
213+
214+
_logger.LogInformation("Loaded data");
215+
}
216+
217+
private async Task SelectWithParameters()
218+
{
219+
await using var db = new MyYdb(BuildOptions());
220+
221+
ulong seriesId = 1;
222+
ulong seasonId = 1;
223+
ulong limit = 3;
224+
225+
var rows = await db.Episodes
226+
.Where(e => e.SeriesId == seriesId && e.SeasonId > seasonId)
227+
.OrderBy(e => e.SeriesId)
228+
.ThenBy(e => e.SeasonId)
229+
.ThenBy(e => e.EpisodeId)
230+
.Take((int)limit)
231+
.Select(e => new { e.SeriesId, e.SeasonId, e.EpisodeId, e.AirDate, e.Title })
232+
.ToListAsync();
233+
234+
_logger.LogInformation("Selected rows:");
235+
foreach (var r in rows)
236+
_logger.LogInformation(
237+
"series_id: {series_id}, season_id: {season_id}, episode_id: {episode_id}, air_date: {air_date}, title: {title}",
238+
r.SeriesId, r.SeasonId, r.EpisodeId, r.AirDate, r.Title);
239+
}
240+
241+
private async Task RetryPolicy()
242+
{
243+
var policy = Policy
244+
.Handle<Exception>(_ => true)
245+
.WaitAndRetryAsync(10, _ => TimeSpan.FromSeconds(1));
246+
247+
await policy.ExecuteAsync(async () =>
248+
{
249+
await using var db = new MyYdb(BuildOptions());
250+
251+
var statsRaw = await db.Episodes
252+
.GroupBy(e => new { e.SeriesId, e.SeasonId })
253+
.Select(g => new
254+
{
255+
SeriesId = g.Key.SeriesId,
256+
SeasonId = g.Key.SeasonId,
257+
Cnt = g.Count()
258+
})
259+
.ToListAsync();
260+
261+
var stats = statsRaw
262+
.OrderBy(x => x.SeriesId)
263+
.ThenBy(x => x.SeasonId);
264+
265+
foreach (var x in stats)
266+
_logger.LogInformation("series_id: {series_id}, season_id: {season_id}, cnt: {cnt}",
267+
x.SeriesId, x.SeasonId, x.Cnt);
268+
});
269+
}
270+
271+
private async Task InteractiveTransaction()
272+
{
273+
await using var db = new MyYdb(BuildOptions());
274+
using var tr = await db.BeginTransactionAsync();
275+
276+
await db.InsertAsync(new Episode
277+
{
278+
SeriesId = 2, SeasonId = 5, EpisodeId = 13,
279+
Title = "Test Episode", AirDate = new DateTime(2018, 08, 27)
280+
});
281+
await db.InsertAsync(new Episode
282+
{
283+
SeriesId = 2, SeasonId = 5, EpisodeId = 21,
284+
Title = "Test 21", AirDate = new DateTime(2018, 08, 27)
285+
});
286+
await db.InsertAsync(new Episode
287+
{
288+
SeriesId = 2, SeasonId = 5, EpisodeId = 22,
289+
Title = "Test 22", AirDate = new DateTime(2018, 08, 27)
290+
});
291+
292+
await tr.CommitAsync();
293+
_logger.LogInformation("Commit transaction");
294+
295+
string title21 = await db.Episodes
296+
.Where(e => e.SeriesId == 2 && e.SeasonId == 5 && e.EpisodeId == 21)
297+
.Select(e => e.Title)
298+
.SingleAsync();
299+
_logger.LogInformation("New episode title: {title}", title21);
300+
301+
string title22 = await db.Episodes
302+
.Where(e => e.SeriesId == 2 && e.SeasonId == 5 && e.EpisodeId == 22)
303+
.Select(e => e.Title)
304+
.SingleAsync();
305+
_logger.LogInformation("New episode title: {title}", title22);
306+
307+
string title13 = await db.Episodes
308+
.Where(e => e.SeriesId == 2 && e.SeasonId == 5 && e.EpisodeId == 13)
309+
.Select(e => e.Title)
310+
.SingleAsync();
311+
_logger.LogInformation("Updated episode title: {title}", title13);
312+
}
313+
314+
private async Task TlsConnectionExample()
315+
{
316+
if (!_settings.UseTls)
317+
{
318+
_logger.LogInformation("Tls example was ignored");
319+
return;
320+
}
321+
322+
var caPath = Path.Combine(
323+
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "ca.pem");
324+
var tlsCs = $"Host={_settings.Host};Port={_settings.TlsPort};RootCertificate={caPath}";
325+
await using var db = new MyYdb(BuildOptions(tlsCs));
326+
327+
var rows = await db.Seasons
328+
.Where(sa => sa.SeriesId == 1)
329+
.Join(db.Series, sa => sa.SeriesId, sr => sr.SeriesId,
330+
(sa, sr) => new { SeasonTitle = sa.Title, SeriesTitle = sr.Title, sr.SeriesId, sa.SeasonId })
331+
.OrderBy(x => x.SeriesId).ThenBy(x => x.SeasonId)
332+
.ToListAsync();
333+
334+
foreach (var r in rows)
335+
_logger.LogInformation(
336+
"season_title: {SeasonTitle}, series_title: {SeriesTitle}, series_id: {SeriesId}, season_id: {SeasonId}",
337+
r.SeasonTitle, r.SeriesTitle, r.SeriesId, r.SeasonId);
338+
}
339+
340+
private async Task ConnectionWithLoggerFactory()
341+
{
342+
await using var db = new MyYdb(BuildOptions(
343+
$"Host={_settings.Host};Port={_settings.Port}"));
344+
345+
db.OnTraceConnection = ti =>
346+
{
347+
switch (ti.TraceInfoStep)
348+
{
349+
case TraceInfoStep.BeforeExecute:
350+
_logger.LogInformation("BeforeExecute: {sql}", ti.SqlText);
351+
break;
352+
case TraceInfoStep.AfterExecute:
353+
_logger.LogInformation("AfterExecute: {time} {records} recs", ti.ExecutionTime, ti.RecordsAffected);
354+
break;
355+
case TraceInfoStep.Error:
356+
_logger.LogError(ti.Exception, "SQL error");
357+
break;
358+
}
359+
};
360+
361+
_logger.LogInformation("Dropping tables of examples");
362+
try { await db.DropTableAsync<Episode>(); } catch { /* ignore */ }
363+
try { await db.DropTableAsync<Season>(); } catch { /* ignore */ }
364+
try { await db.DropTableAsync<Series>(); } catch { /* ignore */ }
365+
_logger.LogInformation("Dropped tables of examples");
366+
}
367+
}

0 commit comments

Comments
 (0)