Breeze / breeze.server.net

Breeze support for .NET servers
MIT License
76 stars 62 forks source link

Many-to-many EF metadata maps Dictionary to "Dictionary'2" which is not a valid TS class name #187

Open OzBob opened 1 year ago

OzBob commented 1 year ago

Using EF to create a many-to-many with join table as per https://learn.microsoft.com/en-us/ef/core/modeling/relationships/many-to-many#examples

Like this,

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasMany(e => e.Tags)
        .WithMany(e => e.Posts)
        .UsingEntity(
            "PostTag",
            l => l.HasOne(typeof(Tag)).WithMany().HasForeignKey("TagsId").HasPrincipalKey(nameof(Tag.Id)),
            r => r.HasOne(typeof(Post)).WithMany().HasForeignKey("PostsId").HasPrincipalKey(nameof(Post.Id)),
            j => j.HasKey("PostsId", "TagsId"));
}

Generates metadata as JSON:

{
            "autoGeneratedKeyType": "None",
            "dataProperties": [
                {
                    "dataType": "Int32",
                    "isNullable": false,
                    "isPartOfKey": true,
                    "nameOnServer": "PostsPostId",
                    "validators": [
                        {
                            "name": "required"
                        },
                        {
                            "name": "int32"
                        }
                    ]
                },
                {
                    "dataType": "Int32",
                    "isNullable": false,
                    "isPartOfKey": true,
                    "nameOnServer": "TagsTagId",
                    "validators": [
                        {
                            "name": "required"
                        },
                        {
                            "name": "int32"
                        }
                    ]
                }
            ],
            "isComplexType": false,
            "namespace": "System.Collections.Generic",
            "navigationProperties": [
            ],
            "shortName": "Dictionary`2"
        },

Using the

const tsGen = require("breeze-entity-generator/tsgen-core");
tsGen.generate({
  inputFileName: "../input-metadata.json",
  outputFolder: "./",
  camelCase: true,
  baseClassName: "BaseEntity",
  kebabCaseFileNames: true,
  codePrefix: "tst",
});

Generates the following TS files: file name: './dictionary-2'

export class Dictionary&#x60;2 extends PortalBaseEntity  {
export { Dictionary&#x60;2 } from './dictionary-2';
  1. can a many-to-many be manipulate to not use a generic dictionary
  2. can tsgen-core generate substitute all characters for class names into a valid range? [a-zA-Z0-9]
steveschmitt commented 1 year ago

When using Breeze, many-to-many relationships must map the join entity as a separate class. In the classic Author - Book relationship, you need to map the AuthorBook class:

    public class Book
    {
        public int Id { get; set; }
        public ICollection<AuthorBook> AuthorBooks { get; set; }
    }

    public class Author
    {
        public int Id { get; set; }
        public ICollection<AuthorBook> AuthorBooks { get; set; }
    }

    public class AuthorBook
    {
        public int BookId { get; set; }
        public int AuthorId { get; set; }
        public Book Book { get; set; }
        public Author Author { get; set; }
    }

In your example, you would need to map the PostTag entity.

In EF, the PostTag join entity is invisible; EF doesn’t need an explicit class, because it can infer its existence from the PostTag table, and can create new entries in the PostTag table to create new relationships.

In Breeze, the client does not have direct access to the database, so the PostTag join entity must be represented as a separate entity.