| | | 1 | | namespace ZhEaIsNsAaBn.DbSeeder; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// The seed view of one entity type: its table, managed fields, data columns and match key — resolved with the same rul |
| | | 5 | | /// uses to bind data files (seed configuration → attributes → interfaces; computed / generated-on-update / ignored colu |
| | | 6 | | /// The design tools export through it, so what they write is exactly what the runtime accepts. |
| | | 7 | | /// </summary> |
| | | 8 | | internal sealed class SeedEntityShape |
| | | 9 | | { |
| | | 10 | | public required IEntityType EntityType { get; init; } |
| | | 11 | | |
| | | 12 | | public required SeedTable Table { get; init; } |
| | | 13 | | |
| | | 14 | | public required SeedEntityRoles Roles { get; init; } |
| | | 15 | | |
| | | 16 | | /// Managed fields the entity maps (role → column). |
| | | 17 | | public required IReadOnlyDictionary<SeedRole, SeedColumn> Managed { get; init; } |
| | | 18 | | |
| | | 19 | | /// Data columns in EF model order (match key included; managed and skipped columns left out). |
| | | 20 | | public required IReadOnlyList<SeedColumn> DataColumns { get; init; } |
| | | 21 | | |
| | | 22 | | /// Whether <see cref="SeedTable.MatchColumns"/> is a configured business key (written as <c>MatchBy</c>). |
| | | 23 | | public required bool IsBusinessKey { get; init; } |
| | | 24 | | |
| | | 25 | | |
| | | 26 | | /// <summary>Resolves the shape of <paramref name="entityType"/>.</summary> |
| | | 27 | | /// <exception cref="InvalidOperationException">Owned / shared / inheritance entity, no table, or a configured <c>Ma |
| | | 28 | | public static SeedEntityShape For( IEntityType entityType, SeedConfiguration configuration ) |
| | | 29 | | { |
| | | 30 | | // The binder is the single source of the rules: bind an empty table file of the entity and read what it resolve |
| | 981 | 31 | | var file = new SeedTableFile { Entity = entityType.Name }; |
| | 981 | 32 | | var bound = SeedMigrationBinder.BindTable( entityType.Model, configuration, $"({entityType.Name})", file ); |
| | | 33 | | |
| | 981 | 34 | | if ( bound.IsFailure ) { throw new InvalidOperationException( Message( bound.Errors[ 0 ] ) ); } |
| | | 35 | | |
| | | 36 | | |
| | 981 | 37 | | var table = bound.Result!; |
| | 981 | 38 | | var store = StoreObjectIdentifier.Table( table.Table.Name, table.Table.Schema ); |
| | 981 | 39 | | var managed = table.Managed.Values.Select( c => c.Property ).ToHashSet(); |
| | 981 | 40 | | var columns = entityType.GetProperties() |
| | 981 | 41 | | .Where( p => !managed.Contains( p ) && !SeedMigrationBinder.IsSkipped( p, store, table.R |
| | 981 | 42 | | .Select( p => SeedMigrationBinder.Column( p, store ) ) |
| | 981 | 43 | | .ToList(); |
| | | 44 | | |
| | 981 | 45 | | return new SeedEntityShape |
| | 981 | 46 | | { |
| | 981 | 47 | | EntityType = entityType, |
| | 981 | 48 | | Table = table.Table, |
| | 981 | 49 | | Roles = table.Roles, |
| | 981 | 50 | | Managed = table.Managed, |
| | 981 | 51 | | DataColumns = columns, |
| | 981 | 52 | | IsBusinessKey = table.MatchesByBusinessKey |
| | 981 | 53 | | }; |
| | | 54 | | } |
| | | 55 | | |
| | | 56 | | |
| | 0 | 57 | | private static string Message( Error error ) => error.AdditionalData.TryGetValue( "Reason", out var reason ) ? $"{er |
| | | 58 | | } |