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

loresoft / EntityFrameworkCore.Generator / 27760980405

18 Jun 2026 12:56PM UTC coverage: 75.418% (+0.7%) from 74.693%
27760980405

push

github

pwelter34
fix build

1007 of 1723 branches covered (58.44%)

Branch coverage included in aggregate %.

4221 of 5209 relevant lines covered (81.03%)

1242.99 hits per line

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

93.98
/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)
161✔
12
    {
13
        _entity = entity;
161✔
14
    }
161✔
15

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

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

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

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

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

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

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

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

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

60
        if (Options.Data.Entity.Document)
161✔
61
        {
62
            GenerateClassDocumentation();
138✔
63
        }
64
        if (Options.Data.Entity.MappingAttributes)
161✔
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}");
161✔
72

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

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

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

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

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

92
    }
161✔
93

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

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

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

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

111
        using (CodeBuilder.Indent())
161✔
112
        {
113
            CodeBuilder.AppendLine("#region Generated Constructor");
161✔
114
            foreach (var relationship in relationships)
466✔
115
            {
116
                var propertyName = relationship.PropertyName.ToSafeName();
72✔
117

118
                var primaryNamespace = relationship.PrimaryEntity.EntityNamespace;
72✔
119
                var primaryName = relationship.PrimaryEntity.EntityClass.ToSafeName();
72✔
120
                var primaryFullName = _entity.EntityNamespace != primaryNamespace
72!
121
                    ? $"{primaryNamespace}.{primaryName}"
72✔
122
                    : primaryName;
72✔
123

124
                CodeBuilder.AppendLine($"{propertyName} = new HashSet<{primaryFullName}>();");
72✔
125
            }
126
            CodeBuilder.AppendLine("#endregion");
161✔
127
        }
161✔
128

129
        CodeBuilder.AppendLine("}");
161✔
130
        CodeBuilder.AppendLine();
161✔
131
    }
161✔
132

133
    private void GenerateProperties()
134
    {
135
        CodeBuilder.AppendLine("#region Generated Properties");
161✔
136
        foreach (var property in _entity.Properties)
2,888✔
137
        {
138
            var propertyType = GetPropertyType(property);
1,283✔
139
            var propertyName = property.PropertyName.ToSafeName();
1,283✔
140

141
            if (Options.Data.Entity.Document)
1,283✔
142
            {
143
                GeneratePropertyDocumentation(property);
1,070✔
144
            }
145

146
            if (Options.Data.Entity.MappingAttributes)
1,283✔
147
            {
148
                if (property.IsPrimaryKey == true)
1,069✔
149
                {
150
                    CodeBuilder.AppendLine("[Key]");
140✔
151
                }
152

153
                if (property.IsConcurrencyToken == true)
1,069✔
154
                {
155
                    CodeBuilder.AppendLine("[ConcurrencyCheck]");
10✔
156
                }
157

158
                CodeBuilder.AppendLine($"[Column(\"{property.ColumnName}\", TypeName = \"{property.NativeType}\")]");
1,069✔
159

160
                if (property.IsIdentity == true)
1,069✔
161
                {
162
                    CodeBuilder.AppendLine("[DatabaseGenerated(DatabaseGeneratedOption.Identity)]");
59✔
163
                }
164
                else if (property.IsRowVersion == true || property.IsComputed == true)
1,010✔
165
                {
166
                    CodeBuilder.AppendLine("[DatabaseGenerated(DatabaseGeneratedOption.Computed)]");
28✔
167
                }
168
            }
169

170
            if (property.IsNullable == true && (property.SystemType.IsValueType || Options.Project.Nullable))
1,283✔
171
                CodeBuilder.AppendLine($"public {ToNullablePropertyType(propertyType)} {propertyName} {{ get; set; }}");
542✔
172
            else if (Options.Project.Nullable && !property.SystemType.IsValueType)
741✔
173
                CodeBuilder.AppendLine($"public {propertyType} {propertyName} {{ get; set; }} = null!;");
152✔
174
            else
175
                CodeBuilder.AppendLine($"public {propertyType} {propertyName} {{ get; set; }}");
589✔
176

177
            CodeBuilder.AppendLine();
1,283✔
178
        }
179
        CodeBuilder.AppendLine("#endregion");
161✔
180
        CodeBuilder.AppendLine();
161✔
181
    }
161✔
182

183
    private static string GetPropertyType(Property property)
184
    {
185
        return property.SystemTypeName.HasValue()
1,283✔
186
            ? property.SystemTypeName
1,283✔
187
            : property.SystemType.ToType();
1,283✔
188
    }
189

190
    private static string ToNullablePropertyType(string propertyType)
191
    {
192
        return propertyType.EndsWith('?')
542!
193
            ? propertyType
542✔
194
            : propertyType + "?";
542✔
195
    }
196

197
    private void GenerateClassDocumentation()
198
    {
199
        var entityName = ToXmlText(_entity.EntityClass);
138✔
200
        var sourceName = ToXmlText(GetQualifiedTableName());
138✔
201
        var sourceType = _entity.IsView ? "view" : "table";
138✔
202

203
        CodeBuilder.AppendLine("/// <summary>");
138✔
204

205
        if (sourceName.HasValue())
138!
206
            CodeBuilder.AppendLine($"/// Represents the <c>{entityName}</c> entity mapped to the <c>{sourceName}</c> {sourceType}.");
138✔
207
        else
208
            CodeBuilder.AppendLine($"/// Represents the <c>{entityName}</c> entity.");
×
209

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

213
    private void GenerateConstructorDocumentation(string entityClass, bool initializesCollections)
214
    {
215
        CodeBuilder.AppendLine("/// <summary>");
138✔
216

217
        if (initializesCollections)
138✔
218
            CodeBuilder.AppendLine($"/// Initializes a new instance of the <see cref=\"{entityClass}\"/> class and its collection navigation properties.");
29✔
219
        else
220
            CodeBuilder.AppendLine($"/// Initializes a new instance of the <see cref=\"{entityClass}\"/> class.");
109✔
221

222
        CodeBuilder.AppendLine("/// </summary>");
138✔
223
    }
138✔
224

225
    private void GeneratePropertyDocumentation(Property property)
226
    {
227
        var propertyName = ToXmlText(property.PropertyName);
1,070✔
228
        var columnName = ToXmlText(property.ColumnName);
1,070✔
229

230
        CodeBuilder.AppendLine("/// <summary>");
1,070✔
231

232
        if (columnName.HasValue())
1,070!
233
            CodeBuilder.AppendLine($"/// Gets or sets the <c>{propertyName}</c> value mapped to the <c>{columnName}</c> column.");
1,070✔
234
        else
235
            CodeBuilder.AppendLine($"/// Gets or sets the <c>{propertyName}</c> value.");
×
236

237
        CodeBuilder.AppendLine("/// </summary>");
1,070✔
238
        CodeBuilder.AppendLine("/// <value>");
1,070✔
239
        CodeBuilder.AppendLine($"/// The <c>{propertyName}</c> entity value.");
1,070✔
240
        CodeBuilder.AppendLine("/// </value>");
1,070✔
241
    }
1,070✔
242

243
    private string? GetQualifiedTableName()
244
    {
245
        if (_entity.TableName.IsNullOrEmpty())
138!
246
            return _entity.TableName;
×
247

248
        return _entity.TableSchema.HasValue()
138✔
249
            ? $"{_entity.TableSchema}.{_entity.TableName}"
138✔
250
            : _entity.TableName;
138✔
251
    }
252

253
    private void GenerateRelationshipProperties()
254
    {
255
        CodeBuilder.AppendLine("#region Generated Relationships");
161✔
256
        foreach (var relationship in _entity.Relationships.OrderBy(r => r.PropertyName))
634✔
257
        {
258
            var propertyName = relationship.PropertyName.ToSafeName();
156✔
259
            var primaryNamespace = relationship.PrimaryEntity.EntityNamespace;
156✔
260
            var primaryName = relationship.PrimaryEntity.EntityClass.ToSafeName();
156✔
261
            var primaryFullName = _entity.EntityNamespace != primaryNamespace
156!
262
                ? $"{primaryNamespace}.{primaryName}"
156✔
263
                : primaryName;
156✔
264

265
            if (relationship.Cardinality == Cardinality.Many)
156✔
266
            {
267
                if (Options.Data.Entity.Document)
72✔
268
                {
269
                    GenerateCollectionRelationshipDocumentation(primaryFullName);
60✔
270
                }
271

272
                CodeBuilder.AppendLine($"public virtual ICollection<{primaryFullName}> {propertyName} {{ get; set; }}");
72✔
273
                CodeBuilder.AppendLine();
72✔
274
            }
275
            else
276
            {
277
                if (Options.Data.Entity.Document)
84✔
278
                {
279
                    GenerateReferenceRelationshipDocumentation(primaryFullName);
68✔
280

281
                    foreach (var property in relationship.Properties)
278✔
282
                    {
283
                        var relatedPropertyName = property.PropertyName.ToSafeName();
71✔
284
                        CodeBuilder.AppendLine($"/// <seealso cref=\"{relatedPropertyName}\" />");
71✔
285
                    }
286
                }
287

288
                if (!Options.Project.Nullable)
84✔
289
                    CodeBuilder.AppendLine($"public virtual {primaryFullName} {propertyName} {{ get; set; }}");
17✔
290
                else if (relationship.Cardinality == Cardinality.One)
67✔
291
                    CodeBuilder.AppendLine($"public virtual {primaryFullName} {propertyName} {{ get; set; }} = null!;");
53✔
292
                else
293
                    CodeBuilder.AppendLine($"public virtual {primaryFullName}? {propertyName} {{ get; set; }}");
14✔
294

295
                CodeBuilder.AppendLine();
84✔
296
            }
297
        }
298

299
        CodeBuilder.AppendLine("#endregion");
161✔
300
        CodeBuilder.AppendLine();
161✔
301
    }
161✔
302

303
    private void GenerateCollectionRelationshipDocumentation(string primaryFullName)
304
    {
305
        CodeBuilder.AppendLine("/// <summary>");
60✔
306
        CodeBuilder.AppendLine($"/// Gets or sets the related <see cref=\"{primaryFullName}\" /> entity collection.");
60✔
307
        CodeBuilder.AppendLine("/// </summary>");
60✔
308
        CodeBuilder.AppendLine("/// <value>");
60✔
309
        CodeBuilder.AppendLine($"/// The related <see cref=\"{primaryFullName}\" /> entity collection.");
60✔
310
        CodeBuilder.AppendLine("/// </value>");
60✔
311
    }
60✔
312

313
    private void GenerateReferenceRelationshipDocumentation(string primaryFullName)
314
    {
315
        CodeBuilder.AppendLine("/// <summary>");
68✔
316
        CodeBuilder.AppendLine($"/// Gets or sets the related <see cref=\"{primaryFullName}\" /> entity.");
68✔
317
        CodeBuilder.AppendLine("/// </summary>");
68✔
318
        CodeBuilder.AppendLine("/// <value>");
68✔
319
        CodeBuilder.AppendLine($"/// The related <see cref=\"{primaryFullName}\" /> entity.");
68✔
320
        CodeBuilder.AppendLine("/// </value>");
68✔
321
    }
68✔
322
}
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