Skip to content

Commit 2a50b3a

Browse files
authored
Merge pull request #194 from gpender/@feature/transform-mapping-improvements
Add .ToTable and .HasColumnName methods when using Transforms. Generate HasKey if key property transformed.
2 parents 2c33f40 + a946d4e commit 2a50b3a

File tree

6 files changed

+503
-25
lines changed

6 files changed

+503
-25
lines changed

src/EntityFrameworkCore.Scaffolding.Handlebars/HbsCSharpDbContextGenerator.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -493,17 +493,25 @@ private void GenerateKey(IKey key, IEntityType entityType, IndentedStringBuilder
493493
if (key.Properties.Count == 1
494494
&& annotations.Count == 0)
495495
{
496+
bool propertyNameOverriden = false;
497+
foreach (var property in key.Properties)
498+
{
499+
var transformedKeyName = EntityTypeTransformationService.TransformPropertyName(entityType, property.Name, property.DeclaringType.Name);
500+
propertyNameOverriden = !property.Name.Equals(transformedKeyName);
501+
if (propertyNameOverriden) break;
502+
}
503+
496504
if (key is IConventionKey concreteKey
497505
&& concreteKey.Properties.SequenceEqual(
498506
KeyDiscoveryConvention.DiscoverKeyProperties(
499507
concreteKey.DeclaringEntityType,
500-
concreteKey.DeclaringEntityType.GetProperties())))
508+
concreteKey.DeclaringEntityType.GetProperties()))
509+
&& UseDataAnnotations || !propertyNameOverriden)
501510
{
502511
return;
503512
}
504513

505-
if (!explicitName
506-
&& UseDataAnnotations)
514+
if (!explicitName && UseDataAnnotations)
507515
{
508516
return;
509517
}
@@ -534,9 +542,13 @@ private void GenerateTableName(IEntityType entityType, IndentedStringBuilder sb)
534542
var schema = entityType.GetSchema();
535543
var defaultSchema = entityType.Model.GetDefaultSchema();
536544

545+
var transformedTableName = EntityTypeTransformationService.TransformTypeEntityName(tableName);
546+
var tableNameOverriden = tableName != null && !tableName.Equals(transformedTableName);
547+
537548
var explicitSchema = schema != null && schema != defaultSchema;
538549
var explicitTable = explicitSchema || tableName != null && tableName != entityType.GetDbSetName();
539-
if (explicitTable)
550+
if (!explicitTable && tableName != null && tableNameOverriden) explicitTable = true;
551+
if (explicitTable && tableName != null)
540552
{
541553
var parameterString = CSharpHelper.Literal(tableName);
542554
if (explicitSchema)
@@ -555,7 +567,7 @@ private void GenerateTableName(IEntityType entityType, IndentedStringBuilder sb)
555567
var explicitViewSchema = viewSchema != null && viewSchema != defaultSchema;
556568
var explicitViewTable = explicitViewSchema || viewName != null;
557569

558-
if (explicitViewTable)
570+
if (explicitViewTable && viewName != null)
559571
{
560572
var parameterString = CSharpHelper.Literal(viewName);
561573
if (explicitViewSchema)
@@ -596,11 +608,16 @@ private void GenerateIndex(IEntityType entityType, IIndex index, IndentedStringB
596608

597609
private void GenerateProperty(IEntityType entityType, IProperty property, bool useDataAnnotations, IndentedStringBuilder sb)
598610
{
611+
var propertyName = EntityTypeTransformationService.TransformPropertyName(entityType, property.Name, property.DeclaringType.Name);
599612
var lines = new List<string>
600613
{
601-
$".{nameof(EntityTypeBuilder.Property)}(e => e.{EntityTypeTransformationService.TransformPropertyName(entityType, property.Name, property.DeclaringType.Name)})"
614+
$".{nameof(EntityTypeBuilder.Property)}(e => e.{propertyName})"
602615
};
603-
616+
// Add .HasColumnName Fluent method for remapped columns where UseDataAnnotations is false
617+
if (!propertyName.Equals(property.Name) && !UseDataAnnotations)
618+
{
619+
lines.Add($".HasColumnName(\"{property.Name}\")");
620+
}
604621
var annotations = AnnotationCodeGenerator
605622
.FilterIgnoredAnnotations(property.GetAnnotations())
606623
.ToDictionary(a => a.Name, a => a);

src/EntityFrameworkCore.Scaffolding.Handlebars/HbsCSharpEntityTypeGenerator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,9 +532,10 @@ private void GenerateKeyAttribute(IProperty property)
532532
private void GenerateColumnAttribute(IProperty property)
533533
{
534534
var columnName = property.GetColumnBaseName();
535+
var propertyName = EntityTypeTransformationService.TransformPropertyName(property.DeclaringEntityType, property.Name, property.DeclaringType.Name);
535536
var columnType = property.GetConfiguredColumnType();
536537

537-
var delimitedColumnName = columnName != null && columnName != property.Name ? CSharpHelper.Literal(columnName) : null;
538+
var delimitedColumnName = columnName != null && columnName != propertyName ? CSharpHelper.Literal(columnName) : null;
538539
var delimitedColumnType = columnType != null ? CSharpHelper.Literal(columnType) : null;
539540

540541
if ((delimitedColumnName ?? delimitedColumnType) != null)

test/Scaffolding.Handlebars.Tests/ExpectedContexts.cs

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,90 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
7474
}
7575
";
7676
}
77+
private static class ExpectedContextsWithTransformMappings
78+
{
79+
public static string ContextClass =
80+
@"using System;
81+
using System.Collections.Generic;
82+
using Microsoft.EntityFrameworkCore;
83+
using Microsoft.EntityFrameworkCore.Metadata;
84+
85+
namespace FakeNamespace
86+
{
87+
public partial class FakeDbContext : DbContext
88+
{
89+
public virtual DbSet<CategoryRenamed> Category { get; set; }
90+
public virtual DbSet<ProductRenamed> Product { get; set; }
91+
92+
public FakeDbContext(DbContextOptions<FakeDbContext> options) : base(options)
93+
{
94+
}
95+
96+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
97+
{
98+
if (!optionsBuilder.IsConfigured)
99+
{
100+
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
101+
optionsBuilder.UseSqlServer(""" + Constants.Connections.SqlServerConnection.Replace(@"\",@"\\") + @""");
102+
}
103+
}
104+
105+
protected override void OnModelCreating(ModelBuilder modelBuilder)
106+
{
107+
modelBuilder.Entity<CategoryRenamed>(entity =>
108+
{
109+
entity.HasKey(e => e.CategoryIdRenamed);
110+
111+
entity.ToTable(""Category"");
112+
113+
entity.HasComment(""A category of products"");
114+
115+
entity.Property(e => e.CategoryIdRenamed).HasColumnName(""CategoryId"");
116+
117+
entity.Property(e => e.CategoryNameRenamed)
118+
.HasColumnName(""CategoryName"")
119+
.IsRequired()
120+
.HasMaxLength(15)
121+
.HasComment(""The name of a category"");
122+
});
123+
124+
modelBuilder.Entity<ProductRenamed>(entity =>
125+
{
126+
entity.HasKey(e => e.ProductIdRenamed);
127+
128+
entity.ToTable(""Product"");
77129
130+
entity.HasIndex(e => e.CategoryIdRenamed, ""IX_Product_CategoryId"");
131+
132+
entity.Property(e => e.ProductIdRenamed).HasColumnName(""ProductId"");
133+
134+
entity.Property(e => e.CategoryIdRenamed).HasColumnName(""CategoryId"");
135+
136+
entity.Property(e => e.ProductName)
137+
.IsRequired()
138+
.HasMaxLength(40);
139+
140+
entity.Property(e => e.RowVersion)
141+
.IsRowVersion()
142+
.IsConcurrencyToken();
143+
144+
entity.Property(e => e.UnitPriceRenamed)
145+
.HasColumnName(""UnitPrice"")
146+
.HasColumnType(""money"");
147+
148+
entity.HasOne(d => d.Category)
149+
.WithMany(p => p.Product)
150+
.HasForeignKey(d => d.CategoryIdRenamed);
151+
});
152+
153+
OnModelCreatingPartial(modelBuilder);
154+
}
155+
156+
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
157+
}
158+
}
159+
";
160+
}
78161
private static class ExpectedContextsSupressOnConfiguring
79162
{
80163
public static string ContextClass =
@@ -137,7 +220,81 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
137220
}
138221
";
139222
}
223+
private static class ExpectedContextsSupressOnConfiguringWithTransformMappings
224+
{
225+
public static string ContextClass =
226+
@"using System;
227+
using System.Collections.Generic;
228+
using Microsoft.EntityFrameworkCore;
229+
using Microsoft.EntityFrameworkCore.Metadata;
230+
231+
namespace FakeNamespace
232+
{
233+
public partial class FakeDbContext : DbContext
234+
{
235+
public virtual DbSet<CategoryRenamed> Category { get; set; }
236+
public virtual DbSet<ProductRenamed> Product { get; set; }
237+
238+
public FakeDbContext(DbContextOptions<FakeDbContext> options) : base(options)
239+
{
240+
}
241+
242+
protected override void OnModelCreating(ModelBuilder modelBuilder)
243+
{
244+
modelBuilder.Entity<CategoryRenamed>(entity =>
245+
{
246+
entity.HasKey(e => e.CategoryIdRenamed);
247+
248+
entity.ToTable(""Category"");
249+
250+
entity.HasComment(""A category of products"");
251+
252+
entity.Property(e => e.CategoryIdRenamed).HasColumnName(""CategoryId"");
253+
254+
entity.Property(e => e.CategoryNameRenamed)
255+
.HasColumnName(""CategoryName"")
256+
.IsRequired()
257+
.HasMaxLength(15)
258+
.HasComment(""The name of a category"");
259+
});
260+
261+
modelBuilder.Entity<ProductRenamed>(entity =>
262+
{
263+
entity.HasKey(e => e.ProductIdRenamed);
264+
265+
entity.ToTable(""Product"");
266+
267+
entity.HasIndex(e => e.CategoryIdRenamed, ""IX_Product_CategoryId"");
268+
269+
entity.Property(e => e.ProductIdRenamed).HasColumnName(""ProductId"");
270+
271+
entity.Property(e => e.CategoryIdRenamed).HasColumnName(""CategoryId"");
272+
273+
entity.Property(e => e.ProductName)
274+
.IsRequired()
275+
.HasMaxLength(40);
276+
277+
entity.Property(e => e.RowVersion)
278+
.IsRowVersion()
279+
.IsConcurrencyToken();
280+
281+
entity.Property(e => e.UnitPriceRenamed)
282+
.HasColumnName(""UnitPrice"")
283+
.HasColumnType(""money"");
284+
285+
entity.HasOne(d => d.Category)
286+
.WithMany(p => p.Product)
287+
.HasForeignKey(d => d.CategoryIdRenamed);
288+
});
289+
290+
OnModelCreatingPartial(modelBuilder);
291+
}
140292
293+
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
294+
}
295+
}
296+
";
297+
}
141298
public static class ExpectedContextsWithAnnotations
142299
{
143300
public static string ContextClass =
@@ -190,5 +347,58 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
190347
}
191348
";
192349
}
350+
public static class ExpectedContextsWithAnnotationsAndTransformMappings
351+
{
352+
public static string ContextClass =
353+
@"using System;
354+
using System.Collections.Generic;
355+
using Microsoft.EntityFrameworkCore;
356+
using Microsoft.EntityFrameworkCore.Metadata;
357+
358+
namespace FakeNamespace
359+
{
360+
public partial class FakeDbContext : DbContext
361+
{
362+
public virtual DbSet<CategoryRenamed> Category { get; set; }
363+
public virtual DbSet<ProductRenamed> Product { get; set; }
364+
365+
public FakeDbContext(DbContextOptions<FakeDbContext> options) : base(options)
366+
{
367+
}
368+
369+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
370+
{
371+
if (!optionsBuilder.IsConfigured)
372+
{
373+
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
374+
optionsBuilder.UseSqlServer(""" + Constants.Connections.SqlServerConnection.Replace(@"\",@"\\") + @""");
375+
}
376+
}
377+
378+
protected override void OnModelCreating(ModelBuilder modelBuilder)
379+
{
380+
modelBuilder.Entity<CategoryRenamed>(entity =>
381+
{
382+
entity.HasComment(""A category of products"");
383+
384+
entity.Property(e => e.CategoryNameRenamed).HasComment(""The name of a category"");
385+
});
386+
387+
modelBuilder.Entity<ProductRenamed>(entity =>
388+
{
389+
entity.Property(e => e.RowVersion)
390+
.IsRowVersion()
391+
.IsConcurrencyToken();
392+
});
393+
394+
OnModelCreatingPartial(modelBuilder);
395+
}
396+
397+
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
398+
}
399+
}
400+
";
401+
}
402+
193403
}
194404
}

0 commit comments

Comments
 (0)