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

loresoft / EntityFrameworkCore.Generator / 28023544968

23 Jun 2026 11:40AM UTC coverage: 72.271%. First build
28023544968

Pull #546

github

web-flow
Merge bcd4f9203 into b377f2e8a
Pull Request #546: Closes #545 Add option for additional using statements in the entity

999 of 1873 branches covered (53.34%)

Branch coverage included in aggregate %.

2 of 6 new or added lines in 2 files covered. (33.33%)

4232 of 5365 relevant lines covered (78.88%)

2016.39 hits per line

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

91.47
/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
        if (!Options.Data.Entity.AdditionalUsings.IsNullOrWhiteSpace())
165!
31
        {
NEW
32
            var splittedUsingEntries = Options.Data.Entity.AdditionalUsings.Split(';').Distinct()
×
NEW
33
                .Where(s => !s.IsNullOrWhiteSpace());
×
34

NEW
35
            foreach (var usingEntry in splittedUsingEntries)
×
NEW
36
                CodeBuilder.AppendLine($"using {usingEntry};");
×
37
        }
38
        CodeBuilder.AppendLine();
165✔
39

40
        CodeBuilder.Append($"namespace {_entity.EntityNamespace}");
165✔
41

42
        if (Options.Project.FileScopedNamespace)
165✔
43
        {
44
            CodeBuilder.AppendLine(";");
137✔
45
            CodeBuilder.AppendLine();
137✔
46
            GenerateClass();
137✔
47
        }
48
        else
49
        {
50
            CodeBuilder.AppendLine();
28✔
51
            CodeBuilder.AppendLine("{");
28✔
52

53
            using (CodeBuilder.Indent())
28✔
54
            {
55
                GenerateClass();
28✔
56
            }
28✔
57

58
            CodeBuilder.AppendLine("}");
28✔
59
        }
60

61
        return CodeBuilder.ToString();
165✔
62
    }
63

64
    private void GenerateClass()
65
    {
66
        var entityClass = _entity.EntityClass.ToSafeName();
165✔
67

68
        if (Options.Data.Entity.Document)
165✔
69
        {
70
            GenerateClassDocumentation();
138✔
71
        }
72
        if (Options.Data.Entity.MappingAttributes)
165✔
73
        {
74
            if (_entity.TableSchema.HasValue())
137✔
75
                CodeBuilder.AppendLine($"[Table(\"{_entity.TableName}\", Schema = \"{_entity.TableSchema}\")]");
103✔
76
            else
77
                CodeBuilder.AppendLine($"[Table(\"{_entity.TableName}\")]");
34✔
78
        }
79
        CodeBuilder.AppendLine($"public partial class {entityClass}");
165✔
80

81
        if (_entity.EntityBaseClass.HasValue())
165!
82
        {
83
            var entityBaseClass = _entity.EntityBaseClass.ToSafeName();
×
84
            using (CodeBuilder.Indent())
×
85
                CodeBuilder.AppendLine($": {entityBaseClass}");
×
86
        }
87

88
        CodeBuilder.AppendLine("{");
165✔
89

90
        using (CodeBuilder.Indent())
165✔
91
        {
92
            GenerateConstructor();
165✔
93

94
            GenerateProperties();
165✔
95
            GenerateRelationshipProperties();
165✔
96
        }
165✔
97

98
        CodeBuilder.AppendLine("}");
165✔
99

100
    }
165✔
101

102
    private void GenerateConstructor()
103
    {
104
        var relationships = _entity.Relationships
165✔
105
            .Where(r => r.Cardinality == Cardinality.Many)
165✔
106
            .OrderBy(r => r.PropertyName)
165✔
107
            .ToList();
165✔
108

109
        var entityClass = _entity.EntityClass.ToSafeName();
165✔
110

111
        if (Options.Data.Entity.Document)
165✔
112
        {
113
            GenerateConstructorDocumentation(entityClass, relationships.Count > 0);
138✔
114
        }
115

116
        CodeBuilder.AppendLine($"public {entityClass}()");
165✔
117
        CodeBuilder.AppendLine("{");
165✔
118

119
        using (CodeBuilder.Indent())
165✔
120
        {
121
            CodeBuilder.AppendLine("#region Generated Constructor");
165✔
122
            foreach (var relationship in relationships)
474✔
123
            {
124
                var propertyName = relationship.PropertyName.ToSafeName();
72✔
125

126
                var primaryNamespace = relationship.PrimaryEntity.EntityNamespace;
72✔
127
                var primaryName = relationship.PrimaryEntity.EntityClass.ToSafeName();
72✔
128
                var primaryFullName = _entity.EntityNamespace != primaryNamespace
72!
129
                    ? $"{primaryNamespace}.{primaryName}"
72✔
130
                    : primaryName;
72✔
131

132
                CodeBuilder.AppendLine($"{propertyName} = new HashSet<{primaryFullName}>();");
72✔
133
            }
134
            CodeBuilder.AppendLine("#endregion");
165✔
135
        }
165✔
136

137
        CodeBuilder.AppendLine("}");
165✔
138
        CodeBuilder.AppendLine();
165✔
139
    }
165✔
140

141
    private void GenerateProperties()
142
    {
143
        CodeBuilder.AppendLine("#region Generated Properties");
165✔
144
        foreach (var property in _entity.Properties)
3,030✔
145
        {
146
            var propertyType = GetPropertyType(property);
1,350✔
147
            var propertyName = property.PropertyName.ToSafeName();
1,350✔
148

149
            if (Options.Data.Entity.Document)
1,350✔
150
            {
151
                GeneratePropertyDocumentation(property);
1,074✔
152
            }
153

154
            if (Options.Data.Entity.MappingAttributes)
1,350✔
155
            {
156
                if (property.IsPrimaryKey == true)
1,073✔
157
                {
158
                    CodeBuilder.AppendLine("[Key]");
140✔
159
                }
160

161
                if (property.IsConcurrencyToken == true)
1,073✔
162
                {
163
                    CodeBuilder.AppendLine("[ConcurrencyCheck]");
10✔
164
                }
165

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

168
                if (property.IsIdentity == true)
1,073✔
169
                {
170
                    CodeBuilder.AppendLine("[DatabaseGenerated(DatabaseGeneratedOption.Identity)]");
59✔
171
                }
172
                else if (property.IsRowVersion == true || property.IsComputed == true)
1,014✔
173
                {
174
                    CodeBuilder.AppendLine("[DatabaseGenerated(DatabaseGeneratedOption.Computed)]");
28✔
175
                }
176
            }
177

178
            if (property.IsNullable == true && (property.SystemType.IsValueType || Options.Project.Nullable))
1,350✔
179
                CodeBuilder.AppendLine($"public {ToNullablePropertyType(propertyType)} {propertyName} {{ get; set; }}");
572✔
180
            else if (Options.Project.Nullable && !property.SystemType.IsValueType)
778✔
181
                CodeBuilder.AppendLine($"public {propertyType} {propertyName} {{ get; set; }} = null!;");
161✔
182
            else
183
                CodeBuilder.AppendLine($"public {propertyType} {propertyName} {{ get; set; }}");
617✔
184

185
            CodeBuilder.AppendLine();
1,350✔
186
        }
187
        CodeBuilder.AppendLine("#endregion");
165✔
188
        CodeBuilder.AppendLine();
165✔
189
    }
165✔
190

191
    private static string GetPropertyType(Property property)
192
    {
193
        return property.SystemTypeName.HasValue()
1,350✔
194
            ? property.SystemTypeName
1,350✔
195
            : property.SystemType.ToType();
1,350✔
196
    }
197

198
    private static string ToNullablePropertyType(string propertyType)
199
    {
200
        return propertyType.EndsWith('?')
572!
201
            ? propertyType
572✔
202
            : propertyType + "?";
572✔
203
    }
204

205
    private void GenerateClassDocumentation()
206
    {
207
        var entityName = ToXmlText(_entity.EntityClass);
138✔
208
        var sourceName = ToXmlText(GetQualifiedTableName());
138✔
209
        var sourceType = _entity.IsView ? "view" : "table";
138✔
210

211
        CodeBuilder.AppendLine("/// <summary>");
138✔
212

213
        if (sourceName.HasValue())
138!
214
            CodeBuilder.AppendLine($"/// Represents the <c>{entityName}</c> entity mapped to the <c>{sourceName}</c> {sourceType}.");
138✔
215
        else
216
            CodeBuilder.AppendLine($"/// Represents the <c>{entityName}</c> entity.");
×
217

218
        CodeBuilder.AppendLine("/// </summary>");
138✔
219
    }
138✔
220

221
    private void GenerateConstructorDocumentation(string entityClass, bool initializesCollections)
222
    {
223
        CodeBuilder.AppendLine("/// <summary>");
138✔
224

225
        if (initializesCollections)
138✔
226
            CodeBuilder.AppendLine($"/// Initializes a new instance of the <see cref=\"{entityClass}\"/> class and its collection navigation properties.");
29✔
227
        else
228
            CodeBuilder.AppendLine($"/// Initializes a new instance of the <see cref=\"{entityClass}\"/> class.");
109✔
229

230
        CodeBuilder.AppendLine("/// </summary>");
138✔
231
    }
138✔
232

233
    private void GeneratePropertyDocumentation(Property property)
234
    {
235
        var propertyName = ToXmlText(property.PropertyName);
1,074✔
236
        var columnName = ToXmlText(property.ColumnName);
1,074✔
237

238
        CodeBuilder.AppendLine("/// <summary>");
1,074✔
239

240
        if (columnName.HasValue())
1,074!
241
            CodeBuilder.AppendLine($"/// Gets or sets the <c>{propertyName}</c> value mapped to the <c>{columnName}</c> column.");
1,074✔
242
        else
243
            CodeBuilder.AppendLine($"/// Gets or sets the <c>{propertyName}</c> value.");
×
244

245
        CodeBuilder.AppendLine("/// </summary>");
1,074✔
246
        CodeBuilder.AppendLine("/// <value>");
1,074✔
247
        CodeBuilder.AppendLine($"/// The <c>{propertyName}</c> entity value.");
1,074✔
248
        CodeBuilder.AppendLine("/// </value>");
1,074✔
249
    }
1,074✔
250

251
    private string? GetQualifiedTableName()
252
    {
253
        if (_entity.TableName.IsNullOrEmpty())
138!
254
            return _entity.TableName;
×
255

256
        return _entity.TableSchema.HasValue()
138✔
257
            ? $"{_entity.TableSchema}.{_entity.TableName}"
138✔
258
            : _entity.TableName;
138✔
259
    }
260

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

273
            if (relationship.Cardinality == Cardinality.Many)
156✔
274
            {
275
                if (Options.Data.Entity.Document)
72✔
276
                {
277
                    GenerateCollectionRelationshipDocumentation(primaryFullName);
60✔
278
                }
279

280
                CodeBuilder.AppendLine($"public virtual ICollection<{primaryFullName}> {propertyName} {{ get; set; }}");
72✔
281
                CodeBuilder.AppendLine();
72✔
282
            }
283
            else
284
            {
285
                if (Options.Data.Entity.Document)
84✔
286
                {
287
                    GenerateReferenceRelationshipDocumentation(primaryFullName);
68✔
288

289
                    foreach (var property in relationship.Properties)
278✔
290
                    {
291
                        var relatedPropertyName = property.PropertyName.ToSafeName();
71✔
292
                        CodeBuilder.AppendLine($"/// <seealso cref=\"{relatedPropertyName}\" />");
71✔
293
                    }
294
                }
295

296
                if (!Options.Project.Nullable)
84✔
297
                    CodeBuilder.AppendLine($"public virtual {primaryFullName} {propertyName} {{ get; set; }}");
17✔
298
                else if (relationship.Cardinality == Cardinality.One)
67✔
299
                    CodeBuilder.AppendLine($"public virtual {primaryFullName} {propertyName} {{ get; set; }} = null!;");
53✔
300
                else
301
                    CodeBuilder.AppendLine($"public virtual {primaryFullName}? {propertyName} {{ get; set; }}");
14✔
302

303
                CodeBuilder.AppendLine();
84✔
304
            }
305
        }
306

307
        CodeBuilder.AppendLine("#endregion");
165✔
308
        CodeBuilder.AppendLine();
165✔
309
    }
165✔
310

311
    private void GenerateCollectionRelationshipDocumentation(string primaryFullName)
312
    {
313
        CodeBuilder.AppendLine("/// <summary>");
60✔
314
        CodeBuilder.AppendLine($"/// Gets or sets the related <see cref=\"{primaryFullName}\" /> entity collection.");
60✔
315
        CodeBuilder.AppendLine("/// </summary>");
60✔
316
        CodeBuilder.AppendLine("/// <value>");
60✔
317
        CodeBuilder.AppendLine($"/// The related <see cref=\"{primaryFullName}\" /> entity collection.");
60✔
318
        CodeBuilder.AppendLine("/// </value>");
60✔
319
    }
60✔
320

321
    private void GenerateReferenceRelationshipDocumentation(string primaryFullName)
322
    {
323
        CodeBuilder.AppendLine("/// <summary>");
68✔
324
        CodeBuilder.AppendLine($"/// Gets or sets the related <see cref=\"{primaryFullName}\" /> entity.");
68✔
325
        CodeBuilder.AppendLine("/// </summary>");
68✔
326
        CodeBuilder.AppendLine("/// <value>");
68✔
327
        CodeBuilder.AppendLine($"/// The related <see cref=\"{primaryFullName}\" /> entity.");
68✔
328
        CodeBuilder.AppendLine("/// </value>");
68✔
329
    }
68✔
330
}
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