diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs index 0044819fb0b..35d050dc83b 100644 --- a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs +++ b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs @@ -255,8 +255,8 @@ public virtual string TransformText() this.Write(this.ToStringHelper.ToStringWithCulture(foreignKey.DependentToPrincipal.Name)); this.Write(")."); this.Write(this.ToStringHelper.ToStringWithCulture(foreignKey.IsUnique ? "WithOne" : "WithMany")); - this.Write("(p => p."); - this.Write(this.ToStringHelper.ToStringWithCulture(foreignKey.PrincipalToDependent.Name)); + this.Write("("); + this.Write(this.ToStringHelper.ToStringWithCulture(foreignKey.PrincipalToDependent != null ? $"p => p.{foreignKey.PrincipalToDependent.Name}" : "")); this.Write(")"); this.Write(this.ToStringHelper.ToStringWithCulture(code.Fragment(foreignKeyFluentApiCalls, indent: 4))); this.Write(";\r\n"); @@ -803,7 +803,7 @@ public System.IFormatProvider FormatProvider { get { - return this.formatProviderField; + return this.formatProviderField ; } set { diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt index e46cd7bbf64..bb2116e37b1 100644 --- a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt +++ b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt @@ -210,7 +210,7 @@ public partial class <#= Options.ContextName #> : DbContext WriteLine(""); } #> - entity.HasOne(d => d.<#= foreignKey.DependentToPrincipal.Name #>).<#= foreignKey.IsUnique ? "WithOne" : "WithMany" #>(p => p.<#= foreignKey.PrincipalToDependent.Name #>)<#= code.Fragment(foreignKeyFluentApiCalls, indent: 4) #>; + entity.HasOne(d => d.<#= foreignKey.DependentToPrincipal.Name #>).<#= foreignKey.IsUnique ? "WithOne" : "WithMany" #>(<#= foreignKey.PrincipalToDependent != null ? $"p => p.{foreignKey.PrincipalToDependent.Name}" : "" #>)<#= code.Fragment(foreignKeyFluentApiCalls, indent: 4) #>; <# anyEntityTypeConfiguration = true; } diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs index e8be03c4d58..a9140e6dc9b 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs @@ -1656,6 +1656,101 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) Assert.Equal(new[] { "Id1", "Id2" }, blogNavigation.ForeignKey.PrincipalKey.Properties.Select(p => p.Name)); }); + [ConditionalFact] + public Task Foreign_key_from_keyless_table() + => TestAsync( + modelBuilder => modelBuilder + .Entity("Blog", x => x.Property("Id")) + .Entity("Post", x => x.HasOne("Blog", "Blog").WithMany()), + new ModelCodeGenerationOptions { UseDataAnnotations = true }, + code => + { + AssertFileContents( + @"using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; + +namespace TestNamespace; + +public partial class TestDbContext : DbContext +{ + public TestDbContext() + { + } + + public TestDbContext(DbContextOptions options) + : base(options) + { + } + + public virtual DbSet Blog { get; set; } + + public virtual DbSet Post { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +#warning " + DesignStrings.SensitiveInformationWarning + @" + => optionsBuilder.UseSqlServer(""Initial Catalog=TestDatabase""); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.Property(e => e.Id).UseIdentityColumn(); + }); + + modelBuilder.Entity(entity => + { + entity.HasNoKey(); + + entity.HasIndex(e => e.BlogId, ""IX_Post_BlogId""); + + entity.HasOne(d => d.Blog).WithMany().HasForeignKey(d => d.BlogId); + }); + + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); +} +", + code.ContextFile); + + AssertFileContents( + @"using System; +using System.Collections.Generic; + +namespace TestNamespace; + +public partial class Blog +{ + public int Id { get; set; } +} +", + code.AdditionalFiles.First(f => f.Path == "Blog.cs")); + + AssertFileContents( + @"using System; +using System.Collections.Generic; + +namespace TestNamespace; + +public partial class Post +{ + public int? BlogId { get; set; } + + public virtual Blog Blog { get; set; } +} +", + code.AdditionalFiles.First(f => f.Path == "Post.cs")); + }, + model => + { + var post = model.FindEntityType("TestNamespace.Post"); + var foreignKey = Assert.Single(post.GetForeignKeys()); + Assert.Equal("Blog", foreignKey.DependentToPrincipal.Name); + Assert.Null(foreignKey.PrincipalToDependent); + }); + [ConditionalFact] public Task InverseProperty_when_navigation_property_with_same_type_and_navigation_name() => TestAsync(