Skip to content

Commit 34562a5

Browse files
author
Anthony Sneed
authored
Merge pull request #88 from TrackableEntities/greggbjensen-exclude-tables-option
Exclude tables, Use embedded templates, Supply TemplateData
2 parents 07281a7 + ff38665 commit 34562a5

File tree

68 files changed

+1211
-144
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1211
-144
lines changed

EntityFrameworkCore.Scaffolding.Handlebars.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScaffoldingSample.Api", "sa
2626
EndProject
2727
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScaffoldingSample.TypeScript", "sample\ScaffoldingSample.TypeScript\ScaffoldingSample.TypeScript.csproj", "{2713D6F6-6ADE-4E3F-8D07-30E19C14AD68}"
2828
EndProject
29+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplatesAssembly", "sample\TemplatesAssembly\TemplatesAssembly.csproj", "{BA4575F5-1DDF-4E7D-A06E-09E56703C3FA}"
30+
EndProject
31+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScaffoldingSample.Embedded", "sample\ScaffoldingSample.Embedded\ScaffoldingSample.Embedded.csproj", "{9288FD98-43FC-4E6B-87FC-FC43E8071C07}"
32+
EndProject
2933
Global
3034
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3135
Debug|Any CPU = Debug|Any CPU
@@ -52,6 +56,14 @@ Global
5256
{2713D6F6-6ADE-4E3F-8D07-30E19C14AD68}.Debug|Any CPU.Build.0 = Debug|Any CPU
5357
{2713D6F6-6ADE-4E3F-8D07-30E19C14AD68}.Release|Any CPU.ActiveCfg = Release|Any CPU
5458
{2713D6F6-6ADE-4E3F-8D07-30E19C14AD68}.Release|Any CPU.Build.0 = Release|Any CPU
59+
{BA4575F5-1DDF-4E7D-A06E-09E56703C3FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
60+
{BA4575F5-1DDF-4E7D-A06E-09E56703C3FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
61+
{BA4575F5-1DDF-4E7D-A06E-09E56703C3FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
62+
{BA4575F5-1DDF-4E7D-A06E-09E56703C3FA}.Release|Any CPU.Build.0 = Release|Any CPU
63+
{9288FD98-43FC-4E6B-87FC-FC43E8071C07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
64+
{9288FD98-43FC-4E6B-87FC-FC43E8071C07}.Debug|Any CPU.Build.0 = Debug|Any CPU
65+
{9288FD98-43FC-4E6B-87FC-FC43E8071C07}.Release|Any CPU.ActiveCfg = Release|Any CPU
66+
{9288FD98-43FC-4E6B-87FC-FC43E8071C07}.Release|Any CPU.Build.0 = Release|Any CPU
5567
EndGlobalSection
5668
GlobalSection(SolutionProperties) = preSolution
5769
HideSolutionNode = FALSE
@@ -62,6 +74,8 @@ Global
6274
{02EC28F3-AA15-4429-9D49-6CE1F2ACCEFA} = {B16E9B06-FE29-413E-B98F-6123DCB92394}
6375
{6141959E-72B2-4FA5-AE75-E0053BFE16D1} = {B16E9B06-FE29-413E-B98F-6123DCB92394}
6476
{2713D6F6-6ADE-4E3F-8D07-30E19C14AD68} = {B16E9B06-FE29-413E-B98F-6123DCB92394}
77+
{BA4575F5-1DDF-4E7D-A06E-09E56703C3FA} = {B16E9B06-FE29-413E-B98F-6123DCB92394}
78+
{9288FD98-43FC-4E6B-87FC-FC43E8071C07} = {B16E9B06-FE29-413E-B98F-6123DCB92394}
6579
EndGlobalSection
6680
GlobalSection(ExtensibilityGlobals) = postSolution
6781
SolutionGuid = {15011E43-4689-4DD6-A1F4-C388E5012B58}

README.md

Lines changed: 91 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ Scaffold EF Core models using Handlebars templates.
4343
{
4444
public void ConfigureDesignTimeServices(IServiceCollection services)
4545
{
46-
var options = ReverseEngineerOptions.DbContextAndEntities;
47-
services.AddHandlebarsScaffolding(options);
46+
services.AddHandlebarsScaffolding(options =>
47+
options.ReverseEngineerOptions = ReverseEngineerOptions.DbContextAndEntities);
4848
}
4949
}
5050
```
@@ -66,6 +66,78 @@ Scaffold EF Core models using Handlebars templates.
6666
specific interfaces.
6767
- When you run the _dotnet-ef-dbcontext-scaffold_ command again, you will see your updated reflected in the generated classes.
6868

69+
## Excluded Tables
70+
71+
You can optionally exclude certain tables from code generation. These may also be qualified by schema name.
72+
73+
```csharp
74+
services.AddHandlebarsScaffolding(options =>
75+
{
76+
// Exclude some tables
77+
options.ExcludedTables = new List<string> { "Territory", "dbo.EmployeeTerritories" };
78+
});
79+
```
80+
81+
## Custom Template Data
82+
83+
You may find it useful to add your own custom template data for use in your Handlebars templates. For example, the model namespace is not included by default in the `DbContext` class import statements. To compensate you may wish to add a `models-namespace` template to the **DbImports.hbs** template file.
84+
85+
```hbs
86+
using System;
87+
using Microsoft.EntityFrameworkCore;
88+
using Microsoft.EntityFrameworkCore.Metadata; // Comment
89+
using {{models-namespace}};
90+
```
91+
92+
Likewise you may wish to specify the name of a model base class in the same way.
93+
94+
```hbs
95+
public partial class {{class}} : {{base-class}}
96+
{
97+
{{{> constructor}}}
98+
{{> properties}}
99+
}
100+
```
101+
102+
You can then set the value of these templates in the `TemplateData` property of `HandlebarsScaffoldingOptions`.
103+
104+
```csharp
105+
services.AddHandlebarsScaffolding(options =>
106+
{
107+
// Add custom template data
108+
options.TemplateData = new Dictionary<string, object>
109+
{
110+
{ "models-namespace", "ScaffoldingSample.Models" },
111+
{ "base-class", "EntityBase" }
112+
};
113+
});
114+
```
115+
## Embedded Templates
116+
117+
Handlebars templates may be embdedded in a separate .NET Standard project that can be shared among multiple .NET Core scaffolding projects. Simply copy the **CodeTemplates** folder to the .NET Standard project and edit the .csproj file to embed them as a resource in the assembly.
118+
119+
```xml
120+
<ItemGroup>
121+
<EmbeddedResource Include="CodeTemplates\**\*.hbs" />
122+
</ItemGroup>
123+
```
124+
125+
Then reference the .NET Standard project from the .NET Core projects and specify the templates assembly when adding Handlebars scaffolding in the `ScaffoldingDesignTimeServices` class.
126+
127+
```csharp
128+
public class ScaffoldingDesignTimeServices : IDesignTimeServices
129+
{
130+
public void ConfigureDesignTimeServices(IServiceCollection services)
131+
{
132+
// Get templates assembly
133+
var templatesAssembly = Assembly.Load("TemplatesAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
134+
135+
// Add Handlebars scaffolding using embedded templates templates
136+
services.AddHandlebarsScaffolding(options => options.EmbeddedTemplatesAssembly = templatesAssembly);
137+
}
138+
}
139+
```
140+
69141
## Handlebars Helpers and Transformers
70142

71143
You can register Handlebars helpers in the `ScaffoldingDesignTimeServices` where setup takes place.
@@ -82,15 +154,26 @@ public class ScaffoldingDesignTimeServices : IDesignTimeServices
82154
{
83155
public void ConfigureDesignTimeServices(IServiceCollection services)
84156
{
85-
// Generate both context and entities
86-
var options = ReverseEngineerOptions.DbContextAndEntities;
157+
// Add Handlebars scaffolding templates
158+
services.AddHandlebarsScaffolding(options =>
159+
{
160+
// Generate both context and entities
161+
options.ReverseEngineerOptions = ReverseEngineerOptions.DbContextAndEntities;
162+
163+
// Exclude some tables
164+
options.ExcludedTables = new List<string> { "Territory", "EmployeeTerritories" };
165+
166+
// Add custom template data
167+
options.TemplateData = new Dictionary<string, object>
168+
{
169+
{ "models-namespace", "ScaffoldingSample.Models" },
170+
{ "base-class", "EntityBase" }
171+
};
172+
});
87173

88174
// Register Handlebars helper
89175
var myHelper = (helperName: "my-helper", helperFunction: (Action<TextWriter, Dictionary<string, object>, object[]>) MyHbsHelper);
90176

91-
// Add Handlebars scaffolding templates
92-
services.AddHandlebarsScaffolding(options);
93-
94177
// Add optional Handlebars helpers
95178
services.AddHandlebarsHelpers(myHelper);
96179

@@ -154,7 +237,7 @@ public class ScaffoldingDesignTimeServices : IDesignTimeServices
154237
{
155238
public void ConfigureDesignTimeServices(IServiceCollection services)
156239
{
157-
// Generate both context and entities
240+
// Generate entities only
158241
var options = ReverseEngineerOptions.EntitiesOnly;
159242

160243
// Generate TypeScript files
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
using System;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore.Metadata;
4+
using ScaffoldingSample.Embedded.Models;
5+
6+
namespace ScaffoldingSample.Embedded.Contexts
7+
{
8+
public partial class NorthwindSlimContext : DbContext
9+
{
10+
public virtual DbSet<Category> Category { get; set; }
11+
public virtual DbSet<Customer> Customer { get; set; }
12+
public virtual DbSet<CustomerSetting> CustomerSetting { get; set; }
13+
public virtual DbSet<Employee> Employee { get; set; }
14+
public virtual DbSet<EmployeeTerritories> EmployeeTerritories { get; set; }
15+
public virtual DbSet<Order> Order { get; set; }
16+
public virtual DbSet<OrderDetail> OrderDetail { get; set; }
17+
public virtual DbSet<Product> Product { get; set; }
18+
public virtual DbSet<Territory> Territory { get; set; }
19+
20+
public NorthwindSlimContext(DbContextOptions<NorthwindSlimContext> options) : base(options)
21+
{
22+
}
23+
24+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
25+
{
26+
if (!optionsBuilder.IsConfigured)
27+
{
28+
//#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
29+
optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB; Initial Catalog=NorthwindSlim; Integrated Security=True");
30+
}
31+
}
32+
33+
protected override void OnModelCreating(ModelBuilder modelBuilder)
34+
{
35+
modelBuilder.Entity<Category>(entity =>
36+
{
37+
entity.Property(e => e.CategoryName)
38+
.IsRequired()
39+
.HasMaxLength(15);
40+
});
41+
42+
modelBuilder.Entity<Customer>(entity =>
43+
{
44+
entity.Property(e => e.CustomerId)
45+
.HasMaxLength(5)
46+
.IsFixedLength();
47+
48+
entity.Property(e => e.City).HasMaxLength(15);
49+
50+
entity.Property(e => e.CompanyName)
51+
.IsRequired()
52+
.HasMaxLength(40);
53+
54+
entity.Property(e => e.ContactName).HasMaxLength(30);
55+
56+
entity.Property(e => e.Country).HasMaxLength(15);
57+
});
58+
59+
modelBuilder.Entity<CustomerSetting>(entity =>
60+
{
61+
entity.HasKey(e => e.CustomerId)
62+
.HasName("PK_dbo.CustomerSetting");
63+
64+
entity.Property(e => e.CustomerId)
65+
.HasMaxLength(5)
66+
.IsFixedLength();
67+
68+
entity.Property(e => e.Setting)
69+
.IsRequired()
70+
.HasMaxLength(50);
71+
72+
entity.HasOne(d => d.Customer)
73+
.WithOne(p => p.CustomerSetting)
74+
.HasForeignKey<CustomerSetting>(d => d.CustomerId)
75+
.OnDelete(DeleteBehavior.ClientSetNull)
76+
.HasConstraintName("FK_CustomerSetting_Customer");
77+
});
78+
79+
modelBuilder.Entity<Employee>(entity =>
80+
{
81+
entity.Property(e => e.BirthDate).HasColumnType("datetime");
82+
83+
entity.Property(e => e.City).HasMaxLength(15);
84+
85+
entity.Property(e => e.Country).HasMaxLength(15);
86+
87+
entity.Property(e => e.FirstName)
88+
.IsRequired()
89+
.HasMaxLength(20);
90+
91+
entity.Property(e => e.HireDate).HasColumnType("datetime");
92+
93+
entity.Property(e => e.LastName)
94+
.IsRequired()
95+
.HasMaxLength(20);
96+
});
97+
98+
modelBuilder.Entity<EmployeeTerritories>(entity =>
99+
{
100+
entity.HasKey(e => new { e.EmployeeId, e.TerritoryId })
101+
.HasName("PK_dbo.EmployeeTerritories");
102+
103+
entity.Property(e => e.TerritoryId).HasMaxLength(20);
104+
105+
entity.HasOne(d => d.Employee)
106+
.WithMany(p => p.EmployeeTerritories)
107+
.HasForeignKey(d => d.EmployeeId)
108+
.HasConstraintName("FK_dbo.EmployeeTerritories_dbo.Employee_EmployeeId");
109+
110+
entity.HasOne(d => d.Territory)
111+
.WithMany(p => p.EmployeeTerritories)
112+
.HasForeignKey(d => d.TerritoryId)
113+
.HasConstraintName("FK_dbo.EmployeeTerritories_dbo.Territory_TerritoryId");
114+
});
115+
116+
modelBuilder.Entity<Order>(entity =>
117+
{
118+
entity.Property(e => e.CustomerId)
119+
.HasMaxLength(5)
120+
.IsFixedLength();
121+
122+
entity.Property(e => e.Freight)
123+
.HasColumnType("money")
124+
.HasDefaultValueSql("((0))");
125+
126+
entity.Property(e => e.OrderDate).HasColumnType("datetime");
127+
128+
entity.Property(e => e.ShippedDate).HasColumnType("datetime");
129+
130+
entity.HasOne(d => d.Customer)
131+
.WithMany(p => p.Order)
132+
.HasForeignKey(d => d.CustomerId)
133+
.HasConstraintName("FK_Orders_Customers");
134+
});
135+
136+
modelBuilder.Entity<OrderDetail>(entity =>
137+
{
138+
entity.Property(e => e.Quantity).HasDefaultValueSql("((1))");
139+
140+
entity.Property(e => e.UnitPrice).HasColumnType("money");
141+
142+
entity.HasOne(d => d.Order)
143+
.WithMany(p => p.OrderDetail)
144+
.HasForeignKey(d => d.OrderId)
145+
.OnDelete(DeleteBehavior.ClientSetNull)
146+
.HasConstraintName("FK_Order_Details_Orders");
147+
148+
entity.HasOne(d => d.Product)
149+
.WithMany(p => p.OrderDetail)
150+
.HasForeignKey(d => d.ProductId)
151+
.OnDelete(DeleteBehavior.ClientSetNull)
152+
.HasConstraintName("FK_Order_Details_Products");
153+
});
154+
155+
modelBuilder.Entity<Product>(entity =>
156+
{
157+
entity.Property(e => e.ProductName)
158+
.IsRequired()
159+
.HasMaxLength(40);
160+
161+
entity.Property(e => e.RowVersion).IsRowVersion();
162+
163+
entity.Property(e => e.UnitPrice)
164+
.HasColumnType("money")
165+
.HasDefaultValueSql("((0))");
166+
167+
entity.HasOne(d => d.Category)
168+
.WithMany(p => p.Product)
169+
.HasForeignKey(d => d.CategoryId)
170+
.HasConstraintName("FK_Products_Categories");
171+
});
172+
173+
modelBuilder.Entity<Territory>(entity =>
174+
{
175+
entity.Property(e => e.TerritoryId).HasMaxLength(20);
176+
177+
entity.Property(e => e.TerritoryDescription)
178+
.IsRequired()
179+
.HasMaxLength(50);
180+
});
181+
182+
OnModelCreatingPartial(modelBuilder);
183+
}
184+
185+
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
186+
}
187+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace ScaffoldingSample.Embedded.Models
5+
{
6+
public partial class Category
7+
{
8+
public Category()
9+
{
10+
Product = new HashSet<Product>();
11+
}
12+
13+
public int CategoryId { get; set; }
14+
public string CategoryName { get; set; }
15+
16+
public virtual ICollection<Product> Product { get; set; }
17+
}
18+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace ScaffoldingSample.Embedded.Models
5+
{
6+
public partial class Customer
7+
{
8+
public Customer()
9+
{
10+
Order = new HashSet<Order>();
11+
}
12+
13+
public string CustomerId { get; set; }
14+
public string CompanyName { get; set; }
15+
public string ContactName { get; set; }
16+
public string City { get; set; }
17+
public string Country { get; set; }
18+
19+
public virtual CustomerSetting CustomerSetting { get; set; }
20+
public virtual ICollection<Order> Order { get; set; }
21+
}
22+
}

0 commit comments

Comments
 (0)