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

loresoft / EntityFrameworkCore.Generator / 27767067052

18 Jun 2026 02:35PM UTC coverage: 70.481% (-4.9%) from 75.418%
27767067052

push

github

pwelter34
Update SourceSynchronizer.cs

913 of 1785 branches covered (51.15%)

Branch coverage included in aggregate %.

5 of 6 new or added lines in 1 file covered. (83.33%)

297 existing lines in 10 files now uncovered.

4094 of 5319 relevant lines covered (76.97%)

1291.15 hits per line

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

35.0
/src/EntityFrameworkCore.Generator.Core/Parsing/SourceSynchronizer.cs
1
using EntityFrameworkCore.Generator.Extensions;
2
using EntityFrameworkCore.Generator.Metadata.Generation;
3
using EntityFrameworkCore.Generator.Metadata.Parsing;
4
using EntityFrameworkCore.Generator.Options;
5

6
using Microsoft.Extensions.Logging;
7

8
namespace EntityFrameworkCore.Generator.Parsing;
9

10
public class SourceSynchronizer
11
{
12
    private readonly ILoggerFactory _loggerFactory;
13
    private readonly ILogger _logger;
14

15
    public SourceSynchronizer(ILoggerFactory loggerFactory)
7✔
16
    {
17
        _loggerFactory = loggerFactory;
7✔
18
        _logger = loggerFactory.CreateLogger<SourceSynchronizer>();
7✔
19
    }
7✔
20

21
    public bool UpdateFromSource(EntityContext generatedContext, GeneratorOptions options)
22
    {
23
        if (generatedContext == null)
7!
24
            return false;
×
25

26
        _logger.LogInformation("Parsing existing source for changes ...");
7✔
27

28
        // make sure to update the entities before the context
29
        UpdateFromMapping(generatedContext, options.Data.Mapping.Directory);
7✔
30
        UpdateFromContext(generatedContext, options.Data.Context.Directory);
7✔
31
        UpdateFromModels(generatedContext, options);
7✔
32

33
        return true;
7✔
34
    }
35

36
    private void UpdateFromModels(EntityContext generatedContext, GeneratorOptions options)
37
    {
38
        if (generatedContext == null || options == null)
7!
UNCOV
39
            return;
×
40

41
        var parser = new ModelParser(_loggerFactory);
7✔
42

43
        foreach (var entity in generatedContext.Entities)
334✔
44
        {
45
            options.Variables.Set(entity);
160✔
46

47
            foreach (var model in entity.Models)
1,108✔
48
            {
49
                options.Variables.Set(model);
394✔
50

51
                UpdateFromModel(parser, model, options);
394✔
52

53
                options.Variables.Remove(model);
394✔
54
            }
55

56
            options.Variables.Remove(entity);
160✔
57
        }
58
    }
7✔
59

60
    private void UpdateFromModel(ModelParser parser, Model model, GeneratorOptions options)
61
    {
62
        var modelDirectory = GetModelDirectory(model, options) ?? "Data\\Models";
394!
63
        modelDirectory = NormalizeDirectory(modelDirectory);
394✔
64

65
        if (!Directory.Exists(modelDirectory))
394✔
66
            return;
393✔
67

68
        var modelFile = Path.Combine(modelDirectory, model.ModelClass + ".cs");
1✔
69
        var parsedModel = parser.ParseFile(modelFile);
1✔
70
        if (parsedModel == null || parsedModel.ModelClass != model.ModelClass)
1!
UNCOV
71
            return;
×
72

73
        foreach (var parsedProperty in parsedModel.Properties)
4✔
74
        {
75
            var property = model.Properties.ByProperty(parsedProperty.PropertyName);
1✔
76
            if (property == null)
1✔
77
                continue;
78

79
            _logger.LogInformation(
1✔
80
                "  Preserve attributes for Model Property '{PropertyName}' in Model '{ModelClass}'.",
1✔
81
                parsedProperty.PropertyName,
1✔
82
                model.ModelClass);
1✔
83

84
            model.PropertyAttributes[parsedProperty.PropertyName] = [.. parsedProperty.Attributes];
1✔
85
        }
86
    }
1✔
87

88
    private static string? GetModelDirectory(Model model, GeneratorOptions options)
89
    {
90
        if (model.ModelType == ModelType.Create)
394✔
91
        {
92
            return options.Model.Create.Directory.HasValue()
128!
93
                ? options.Model.Create.Directory
128✔
94
                : options.Model.Shared.Directory;
128✔
95
        }
96

97
        if (model.ModelType == ModelType.Update)
266✔
98
        {
99
            return options.Model.Update.Directory.HasValue()
128!
100
                ? options.Model.Update.Directory
128✔
101
                : options.Model.Shared.Directory;
128✔
102
        }
103

104
        return options.Model.Read.Directory.HasValue()
138✔
105
            ? options.Model.Read.Directory
138✔
106
            : options.Model.Shared.Directory;
138✔
107
    }
108

109

110
    private void UpdateFromContext(EntityContext generatedContext, string? contextDirectory)
111
    {
112
        contextDirectory = NormalizeDirectory(contextDirectory);
7✔
113

114
        if (generatedContext == null
7!
115
            || contextDirectory == null
7✔
116
            || !Directory.Exists(contextDirectory))
7✔
117
        {
118
            return;
7✔
119
        }
120

UNCOV
121
        var parser = new ContextParser(_loggerFactory);
×
122

123
        // search all cs files looking for DbContext.  need this in case of context class rename
124
        ParsedContext? parsedContext = null;
×
125

126
        using var files = Directory.EnumerateFiles(contextDirectory, "*.cs").GetEnumerator();
×
UNCOV
127
        while (files.MoveNext() && parsedContext == null)
×
128
            parsedContext = parser.ParseFile(files.Current);
×
129

UNCOV
130
        if (parsedContext == null)
×
UNCOV
131
            return;
×
132

UNCOV
133
        if (generatedContext.ContextClass != parsedContext.ContextClass)
×
134
        {
UNCOV
135
            _logger.LogInformation(
×
UNCOV
136
                "Rename Context Class'{ContextClass}' to '{ContextClass}'.",
×
UNCOV
137
                generatedContext.ContextClass,
×
UNCOV
138
                parsedContext.ContextClass);
×
139

UNCOV
140
            generatedContext.ContextClass = parsedContext.ContextClass;
×
141
        }
142

UNCOV
143
        foreach (var parsedProperty in parsedContext.Properties)
×
144
        {
UNCOV
145
            var entity = generatedContext.Entities.ByClass(parsedProperty.EntityClass);
×
UNCOV
146
            if (entity == null)
×
147
                continue;
148

UNCOV
149
            if (entity.ContextProperty == parsedProperty.ContextProperty)
×
150
                continue;
151

UNCOV
152
            _logger.LogInformation(
×
UNCOV
153
                "Rename Context Property'{EntityProperty}' to '{ParsedProperty}'.",
×
UNCOV
154
                entity.ContextProperty,
×
UNCOV
155
                parsedProperty.ContextProperty);
×
156

UNCOV
157
            entity.ContextProperty = parsedProperty.ContextProperty;
×
158
        }
UNCOV
159
    }
×
160

161
    private void UpdateFromMapping(EntityContext generatedContext, string? mappingDirectory)
162
    {
163
        mappingDirectory = NormalizeDirectory(mappingDirectory);
7✔
164

165
        if (generatedContext == null
7!
166
            || mappingDirectory == null
7✔
167
            || !Directory.Exists(mappingDirectory))
7✔
168
        {
169
            return;
7✔
170
        }
171

172
        var parser = new MappingParser(_loggerFactory);
×
173

174
        // parse all mapping files
175
        var mappingFiles = Directory.EnumerateFiles(mappingDirectory, "*.cs");
×
UNCOV
176
        var parsedEntities = mappingFiles
×
UNCOV
177
            .Select(parser.ParseFile)
×
UNCOV
178
            .Where(parsedEntity => parsedEntity != null)
×
UNCOV
179
            .ToList();
×
180

181
        // update all entity and property names first because relationships are linked by property names
182
        foreach (var parsedEntity in parsedEntities)
×
183
        {
UNCOV
184
            if (parsedEntity == null)
×
185
                continue;
186

187
            // find entity by table name to support renaming entity
188
            var entity = generatedContext.Entities
×
189
                .ByTable(parsedEntity.TableName, parsedEntity.TableSchema);
×
190

UNCOV
191
            if (entity == null)
×
192
                continue;
193

194
            // sync names
UNCOV
195
            if (entity.MappingClass != parsedEntity.MappingClass)
×
196
            {
UNCOV
197
                _logger.LogInformation(
×
UNCOV
198
                    "  Rename Mapping Class'{EntityClass}' to '{ParsedClass}'.",
×
199
                    entity.MappingClass,
×
200
                    parsedEntity.MappingClass);
×
201

UNCOV
202
                entity.MappingClass = parsedEntity.MappingClass;
×
203
            }
204

205
            RenameEntity(generatedContext, entity.EntityClass, parsedEntity.EntityClass);
×
206

207
            // sync properties
UNCOV
208
            foreach (var parsedProperty in parsedEntity.Properties)
×
209
            {
210
                // find property by column name to support property name rename
UNCOV
211
                var property = entity.Properties.ByColumn(parsedProperty.ColumnName);
×
UNCOV
212
                if (property == null)
×
213
                    continue;
214

UNCOV
215
                RenameProperty(
×
UNCOV
216
                    generatedContext,
×
217
                    entity.EntityClass,
×
218
                    property.PropertyName,
×
UNCOV
219
                    parsedProperty.PropertyName);
×
220
            }
221

222
            // sync relationships
223
            foreach (var parsedRelationship in parsedEntity.Relationships)
×
224
            {
UNCOV
225
                var relationship = entity.Relationships.FirstOrDefault(r => r.RelationshipName == parsedRelationship.RelationshipName && r.IsForeignKey);
×
UNCOV
226
                if (relationship == null)
×
227
                    continue;
228

UNCOV
229
                RenameRelationship(parsedRelationship, relationship);
×
230
            }
231
        }
UNCOV
232
    }
×
233

234
    private static string? NormalizeDirectory(string? directory)
235
    {
236
        if (directory.IsNullOrWhiteSpace() || Path.DirectorySeparatorChar == '\\')
408!
NEW
237
            return directory;
×
238

239
        return directory.Replace('\\', Path.DirectorySeparatorChar);
408✔
240
    }
241

242

243

244
    private void RenameEntity(EntityContext generatedContext, string originalName, string newName)
245
    {
UNCOV
246
        if (originalName == newName)
×
UNCOV
247
            return;
×
248

UNCOV
249
        _logger.LogInformation("  Rename Entity '{OrginalName}' to '{NewName}'.", originalName, newName);
×
UNCOV
250
        foreach (var entity in generatedContext.Entities)
×
251
        {
UNCOV
252
            if (entity.EntityClass == originalName)
×
UNCOV
253
                entity.EntityClass = newName;
×
254
        }
UNCOV
255
    }
×
256

257
    private void RenameProperty(EntityContext generatedContext, string entityName, string originalName, string newName)
258
    {
UNCOV
259
        if (originalName == newName)
×
UNCOV
260
            return;
×
261

UNCOV
262
        _logger.LogInformation("  Rename Property '{OrginalName}' to '{NewName}' in Entity '{EntityName}'.", originalName, newName, entityName);
×
UNCOV
263
        foreach (var entity in generatedContext.Entities)
×
264
        {
UNCOV
265
            if (entity.EntityClass != entityName)
×
266
                continue;
267

UNCOV
268
            var property = entity.Properties.ByProperty(originalName);
×
UNCOV
269
            if (property != null)
×
UNCOV
270
                property.PropertyName = newName;
×
271
        }
272

UNCOV
273
    }
×
274

275
    private void RenameRelationship(ParsedRelationship parsedRelationship, Relationship relationship)
276
    {
UNCOV
277
        if (parsedRelationship.PropertyName.HasValue() && relationship.PropertyName != parsedRelationship.PropertyName)
×
278
        {
UNCOV
279
            _logger.LogInformation("  Rename Property '{OrginalName}' to '{NewName}' in Entity '{EntityName}'.", relationship.PropertyName, parsedRelationship.PropertyName, relationship.Entity.EntityClass);
×
UNCOV
280
            relationship.PropertyName = parsedRelationship.PropertyName;
×
281
        }
282

UNCOV
283
        if (parsedRelationship.PrimaryPropertyName.HasValue() && relationship.PrimaryPropertyName != parsedRelationship.PrimaryPropertyName)
×
284
        {
UNCOV
285
            _logger.LogInformation("  Rename Property '{OrginalName}' to '{NewName}' in Entity '{EntityName}'.", relationship.PrimaryPropertyName, parsedRelationship.PrimaryPropertyName, relationship.PrimaryEntity.EntityClass);
×
UNCOV
286
            relationship.PrimaryPropertyName = parsedRelationship.PrimaryPropertyName;
×
287
        }
288

UNCOV
289
        var primaryEntity = relationship.PrimaryEntity;
×
UNCOV
290
        var primaryRelationship = primaryEntity.Relationships.FirstOrDefault(r => r.RelationshipName == parsedRelationship.RelationshipName && !r.IsForeignKey);
×
291

UNCOV
292
        if (primaryRelationship == null)
×
UNCOV
293
            return;
×
294

UNCOV
295
        if (parsedRelationship.PrimaryPropertyName.HasValue() && primaryRelationship.PropertyName != parsedRelationship.PrimaryPropertyName)
×
296
        {
UNCOV
297
            _logger.LogInformation("  Rename Property '{OrginalName}' to '{NewName}' in Entity '{EntityName}'.", primaryRelationship.PropertyName, parsedRelationship.PrimaryPropertyName, primaryRelationship.Entity.EntityClass);
×
UNCOV
298
            primaryRelationship.PropertyName = parsedRelationship.PrimaryPropertyName;
×
299
        }
300

UNCOV
301
        if (parsedRelationship.PropertyName.HasValue() && primaryRelationship.PrimaryPropertyName != parsedRelationship.PropertyName)
×
302
        {
UNCOV
303
            _logger.LogInformation("  Rename Property '{OrginalName}' to '{NewName}' in Entity '{EntityName}'.", primaryRelationship.PrimaryPropertyName, parsedRelationship.PropertyName, primaryRelationship.PrimaryEntity.EntityClass);
×
UNCOV
304
            primaryRelationship.PrimaryPropertyName = parsedRelationship.PropertyName;
×
305
        }
UNCOV
306
    }
×
307
}
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