• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / EntityFrameworkCore.Generator / 28023205642

23 Jun 2026 11:34AM UTC coverage: 72.234%. First build
28023205642

Pull #550

github

web-flow
Merge a84338e27 into b377f2e8a
Pull Request #550: Closes #549 Add option to generate a PK guid value in the entity class

1003 of 1879 branches covered (53.38%)

Branch coverage included in aggregate %.

6 of 13 new or added lines in 5 files covered. (46.15%)

4234 of 5371 relevant lines covered (78.83%)

2014.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.19
/src/EntityFrameworkCore.Generator.Core/Templates/EntityClassTemplate.cs
1
using EntityFrameworkCore.Generator.Extensions;
2
using EntityFrameworkCore.Generator.Metadata.Generation;
3
using EntityFrameworkCore.Generator.Options;
4

5
namespace EntityFrameworkCore.Generator.Templates;
6

7
public class EntityClassTemplate : CodeTemplateBase
8
{
9
    private readonly Entity _entity;
10

11
    public EntityClassTemplate(Entity entity, GeneratorOptions options) : base(options)
165✔
12
    {
13
        _entity = entity;
165✔
14
    }
165✔
15

16
    public override string WriteCode()
17
    {
18
        CodeBuilder.Clear();
165✔
19

20
        if (Options.Data.Entity.Header.HasValue())
165!
21
            CodeBuilder.AppendLine(Options.Data.Entity.Header).AppendLine();
×
22

23
        CodeBuilder.AppendLine("using System;");
165✔
24
        CodeBuilder.AppendLine("using System.Collections.Generic;");
165✔
25
        if (Options.Data.Entity.MappingAttributes)
165✔
26
        {
27
            CodeBuilder.AppendLine("using System.ComponentModel.DataAnnotations;");
137✔
28
            CodeBuilder.AppendLine("using System.ComponentModel.DataAnnotations.Schema;");
137✔
29
        }
30
        CodeBuilder.AppendLine();
165✔
31

32
        CodeBuilder.Append($"namespace {_entity.EntityNamespace}");
165✔
33

34
        if (Options.Project.FileScopedNamespace)
165✔
35
        {
36
            CodeBuilder.AppendLine(";");
137✔
37
            CodeBuilder.AppendLine();
137✔
38
            GenerateClass();
137✔
39
        }
40
        else
41
        {
42
            CodeBuilder.AppendLine();
28✔
43
            CodeBuilder.AppendLine("{");
28✔
44

45
            using (CodeBuilder.Indent())
28✔
46
            {
47
                GenerateClass();
28✔
48
            }
28✔
49

50
            CodeBuilder.AppendLine("}");
28✔
51
        }
52

53
        return CodeBuilder.ToString();
165✔
54
    }
55

56
    private void GenerateClass()
57
    {
58
        var entityClass = _entity.EntityClass.ToSafeName();
165✔
59

60
        if (Options.Data.Entity.Document)
165✔
61
        {
62
            GenerateClassDocumentation();
138✔
63
        }
64
        if (Options.Data.Entity.MappingAttributes)
165✔
65
        {
66
            if (_entity.TableSchema.HasValue())
137✔
67
                CodeBuilder.AppendLine($"[Table(\"{_entity.TableName}\", Schema = \"{_entity.TableSchema}\")]");
103✔
68
            else
69
                CodeBuilder.AppendLine($"[Table(\"{_entity.TableName}\")]");
34✔
70
        }
71
        CodeBuilder.AppendLine($"public partial class {entityClass}");
165✔
72

73
        if (_entity.EntityBaseClass.HasValue())
165!
74
        {
75
            var entityBaseClass = _entity.EntityBaseClass.ToSafeName();
×
76
            using (CodeBuilder.Indent())
×
77
                CodeBuilder.AppendLine($": {entityBaseClass}");
×
78
        }
79

80
        CodeBuilder.AppendLine("{");
165✔
81

82
        using (CodeBuilder.Indent())
165✔
83
        {
84
            GenerateConstructor();
165✔
85

86
            GenerateProperties();
165✔
87
            GenerateRelationshipProperties();
165✔
88
        }
165✔
89

90
        CodeBuilder.AppendLine("}");
165✔
91

92
    }
165✔
93

94
    private void GenerateConstructor()
95
    {
96
        var relationships = _entity.Relationships
165✔
97
            .Where(r => r.Cardinality == Cardinality.Many)
165✔
98
            .OrderBy(r => r.PropertyName)
165✔
99
            .ToList();
165✔
100

101
        var entityClass = _entity.EntityClass.ToSafeName();
165✔
102

103
        if (Options.Data.Entity.Document)
165✔
104
        {
105
            GenerateConstructorDocumentation(entityClass, relationships.Count > 0);
138✔
106
        }
107

108
        CodeBuilder.AppendLine($"public {entityClass}()");
165✔
109
        CodeBuilder.AppendLine("{");
165✔
110

111
        using (CodeBuilder.Indent())
165✔
112
        {
113
            CodeBuilder.AppendLine("#region Generated Constructor");
165✔
114

115
            if (Options.Data.Entity.GeneratePkValue)
165!
116
            {
NEW
117
                var primaryKeyProperty = _entity.Properties.FirstOrDefault(p => p.IsPrimaryKey == true);
×
118

NEW
119
                if (primaryKeyProperty != null && primaryKeyProperty.DataType == System.Data.DbType.Guid)
×
120
                {
NEW
121
                    var primaryKeyPropertyName = primaryKeyProperty.PropertyName.ToSafeName();
×
122

NEW
123
                    CodeBuilder.AppendLine($"{primaryKeyPropertyName} = Guid.NewGuid();");
×
NEW
124
                    CodeBuilder.AppendLine();
×
125
                }
126
            }
127

128
            foreach (var relationship in relationships)
474✔
129
            {
130
                var propertyName = relationship.PropertyName.ToSafeName();
72✔
131

132
                var primaryNamespace = relationship.PrimaryEntity.EntityNamespace;
72✔
133
                var primaryName = relationship.PrimaryEntity.EntityClass.ToSafeName();
72✔
134
                var primaryFullName = _entity.EntityNamespace != primaryNamespace
72!
135
                    ? $"{primaryNamespace}.{primaryName}"
72✔
136
                    : primaryName;
72✔
137

138
                CodeBuilder.AppendLine($"{propertyName} = new HashSet<{primaryFullName}>();");
72✔
139
            }
140
            CodeBuilder.AppendLine("#endregion");
165✔
141
        }
165✔
142

143
        CodeBuilder.AppendLine("}");
165✔
144
        CodeBuilder.AppendLine();
165✔
145
    }
165✔
146

147
    private void GenerateProperties()
148
    {
149
        CodeBuilder.AppendLine("#region Generated Properties");
165✔
150
        foreach (var property in _entity.Properties)
3,030✔
151
        {
152
            var propertyType = GetPropertyType(property);
1,350✔
153
            var propertyName = property.PropertyName.ToSafeName();
1,350✔
154

155
            if (Options.Data.Entity.Document)
1,350✔
156
            {
157
                GeneratePropertyDocumentation(property);
1,074✔
158
            }
159

160
            if (Options.Data.Entity.MappingAttributes)
1,350✔
161
            {
162
                if (property.IsPrimaryKey == true)
1,073✔
163
                {
164
                    CodeBuilder.AppendLine("[Key]");
140✔
165
                }
166

167
                if (property.IsConcurrencyToken == true)
1,073✔
168
                {
169
                    CodeBuilder.AppendLine("[ConcurrencyCheck]");
10✔
170
                }
171

172
                CodeBuilder.AppendLine($"[Column(\"{property.ColumnName}\", TypeName = \"{property.NativeType}\")]");
1,073✔
173

174
                if (property.IsIdentity == true)
1,073✔
175
                {
176
                    CodeBuilder.AppendLine("[DatabaseGenerated(DatabaseGeneratedOption.Identity)]");
59✔
177
                }
178
                else if (property.IsRowVersion == true || property.IsComputed == true)
1,014✔
179
                {
180
                    CodeBuilder.AppendLine("[DatabaseGenerated(DatabaseGeneratedOption.Computed)]");
28✔
181
                }
182
            }
183

184
            if (property.IsNullable == true && (property.SystemType.IsValueType || Options.Project.Nullable))
1,350✔
185
                CodeBuilder.AppendLine($"public {ToNullablePropertyType(propertyType)} {propertyName} {{ get; set; }}");
572✔
186
            else if (Options.Project.Nullable && !property.SystemType.IsValueType)
778✔
187
                CodeBuilder.AppendLine($"public {propertyType} {propertyName} {{ get; set; }} = null!;");
161✔
188
            else
189
                CodeBuilder.AppendLine($"public {propertyType} {propertyName} {{ get; set; }}");
617✔
190

191
            CodeBuilder.AppendLine();
1,350✔
192
        }
193
        CodeBuilder.AppendLine("#endregion");
165✔
194
        CodeBuilder.AppendLine();
165✔
195
    }
165✔
196

197
    private static string GetPropertyType(Property property)
198
    {
199
        return property.SystemTypeName.HasValue()
1,350✔
200
            ? property.SystemTypeName
1,350✔
201
            : property.SystemType.ToType();
1,350✔
202
    }
203

204
    private static string ToNullablePropertyType(string propertyType)
205
    {
206
        return propertyType.EndsWith('?')
572!
207
            ? propertyType
572✔
208
            : propertyType + "?";
572✔
209
    }
210

211
    private void GenerateClassDocumentation()
212
    {
213
        var entityName = ToXmlText(_entity.EntityClass);
138✔
214
        var sourceName = ToXmlText(GetQualifiedTableName());
138✔
215
        var sourceType = _entity.IsView ? "view" : "table";
138✔
216

217
        CodeBuilder.AppendLine("/// <summary>");
138✔
218

219
        if (sourceName.HasValue())
138!
220
            CodeBuilder.AppendLine($"/// Represents the <c>{entityName}</c> entity mapped to the <c>{sourceName}</c> {sourceType}.");
138✔
221
        else
222
            CodeBuilder.AppendLine($"/// Represents the <c>{entityName}</c> entity.");
×
223

224
        CodeBuilder.AppendLine("/// </summary>");
138✔
225
    }
138✔
226

227
    private void GenerateConstructorDocumentation(string entityClass, bool initializesCollections)
228
    {
229
        CodeBuilder.AppendLine("/// <summary>");
138✔
230

231
        if (initializesCollections)
138✔
232
            CodeBuilder.AppendLine($"/// Initializes a new instance of the <see cref=\"{entityClass}\"/> class and its collection navigation properties.");
29✔
233
        else
234
            CodeBuilder.AppendLine($"/// Initializes a new instance of the <see cref=\"{entityClass}\"/> class.");
109✔
235

236
        CodeBuilder.AppendLine("/// </summary>");
138✔
237
    }
138✔
238

239
    private void GeneratePropertyDocumentation(Property property)
240
    {
241
        var propertyName = ToXmlText(property.PropertyName);
1,074✔
242
        var columnName = ToXmlText(property.ColumnName);
1,074✔
243

244
        CodeBuilder.AppendLine("/// <summary>");
1,074✔
245

246
        if (columnName.HasValue())
1,074!
247
            CodeBuilder.AppendLine($"/// Gets or sets the <c>{propertyName}</c> value mapped to the <c>{columnName}</c> column.");
1,074✔
248
        else
249
            CodeBuilder.AppendLine($"/// Gets or sets the <c>{propertyName}</c> value.");
×
250

251
        CodeBuilder.AppendLine("/// </summary>");
1,074✔
252
        CodeBuilder.AppendLine("/// <value>");
1,074✔
253
        CodeBuilder.AppendLine($"/// The <c>{propertyName}</c> entity value.");
1,074✔
254
        CodeBuilder.AppendLine("/// </value>");
1,074✔
255
    }
1,074✔
256

257
    private string? GetQualifiedTableName()
258
    {
259
        if (_entity.TableName.IsNullOrEmpty())
138!
260
            return _entity.TableName;
×
261

262
        return _entity.TableSchema.HasValue()
138✔
263
            ? $"{_entity.TableSchema}.{_entity.TableName}"
138✔
264
            : _entity.TableName;
138✔
265
    }
266

267
    private void GenerateRelationshipProperties()
268
    {
269
        CodeBuilder.AppendLine("#region Generated Relationships");
165✔
270
        foreach (var relationship in _entity.Relationships.OrderBy(r => r.PropertyName))
642✔
271
        {
272
            var propertyName = relationship.PropertyName.ToSafeName();
156✔
273
            var primaryNamespace = relationship.PrimaryEntity.EntityNamespace;
156✔
274
            var primaryName = relationship.PrimaryEntity.EntityClass.ToSafeName();
156✔
275
            var primaryFullName = _entity.EntityNamespace != primaryNamespace
156!
276
                ? $"{primaryNamespace}.{primaryName}"
156✔
277
                : primaryName;
156✔
278

279
            if (relationship.Cardinality == Cardinality.Many)
156✔
280
            {
281
                if (Options.Data.Entity.Document)
72✔
282
                {
283
                    GenerateCollectionRelationshipDocumentation(primaryFullName);
60✔
284
                }
285

286
                CodeBuilder.AppendLine($"public virtual ICollection<{primaryFullName}> {propertyName} {{ get; set; }}");
72✔
287
                CodeBuilder.AppendLine();
72✔
288
            }
289
            else
290
            {
291
                if (Options.Data.Entity.Document)
84✔
292
                {
293
                    GenerateReferenceRelationshipDocumentation(primaryFullName);
68✔
294

295
                    foreach (var property in relationship.Properties)
278✔
296
                    {
297
                        var relatedPropertyName = property.PropertyName.ToSafeName();
71✔
298
                        CodeBuilder.AppendLine($"/// <seealso cref=\"{relatedPropertyName}\" />");
71✔
299
                    }
300
                }
301

302
                if (!Options.Project.Nullable)
84✔
303
                    CodeBuilder.AppendLine($"public virtual {primaryFullName} {propertyName} {{ get; set; }}");
17✔
304
                else if (relationship.Cardinality == Cardinality.One)
67✔
305
                    CodeBuilder.AppendLine($"public virtual {primaryFullName} {propertyName} {{ get; set; }} = null!;");
53✔
306
                else
307
                    CodeBuilder.AppendLine($"public virtual {primaryFullName}? {propertyName} {{ get; set; }}");
14✔
308

309
                CodeBuilder.AppendLine();
84✔
310
            }
311
        }
312

313
        CodeBuilder.AppendLine("#endregion");
165✔
314
        CodeBuilder.AppendLine();
165✔
315
    }
165✔
316

317
    private void GenerateCollectionRelationshipDocumentation(string primaryFullName)
318
    {
319
        CodeBuilder.AppendLine("/// <summary>");
60✔
320
        CodeBuilder.AppendLine($"/// Gets or sets the related <see cref=\"{primaryFullName}\" /> entity collection.");
60✔
321
        CodeBuilder.AppendLine("/// </summary>");
60✔
322
        CodeBuilder.AppendLine("/// <value>");
60✔
323
        CodeBuilder.AppendLine($"/// The related <see cref=\"{primaryFullName}\" /> entity collection.");
60✔
324
        CodeBuilder.AppendLine("/// </value>");
60✔
325
    }
60✔
326

327
    private void GenerateReferenceRelationshipDocumentation(string primaryFullName)
328
    {
329
        CodeBuilder.AppendLine("/// <summary>");
68✔
330
        CodeBuilder.AppendLine($"/// Gets or sets the related <see cref=\"{primaryFullName}\" /> entity.");
68✔
331
        CodeBuilder.AppendLine("/// </summary>");
68✔
332
        CodeBuilder.AppendLine("/// <value>");
68✔
333
        CodeBuilder.AppendLine($"/// The related <see cref=\"{primaryFullName}\" /> entity.");
68✔
334
        CodeBuilder.AppendLine("/// </value>");
68✔
335
    }
68✔
336
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc