KrisPetkov wrote:Guys, I have one more question related to the linq2db and FluentMigrator entanglement.
Are you familiar with FluentMigratorMetadataReader.cs and NameCompatibilityManager.cs classes and what is he main idea behind them?
It is somehow related to the table/column naming, migrations and linq2db entities matching but I cannot grasp the whole idea of this approach. And isn't this too heavy to constantly iterating some classes, propeties, names etc.
P.S. do you know some good comprehensive tutorial for linq2db because their documentation is really not enough to learn how everything works in depth and what are the options that you have
I have not looked into those things in more details. However, by far what I have seen, both are related to the way Nop data layer handles data mapping. Previously, in order to get the repository to working with new entity, you would have to include the entity class, the mapping class, then add the mapping class to the plugin object context, and then register the dependency for the repository. With this new release, Nop cuts down the steps of setting up mapping class, plugin object context, and the registration for dependency of the repository. The idea of FluentMigratorMetadataReader class is to scan for new schema migration/entities, and then automatically map that entity using linq2db instead (In the comment, it is said "LINQ To DB metadata reader for schema created by FluentMigrator"). At the same time, NameCompatibilityManager class is to help backward compatibility with the mapping and resolves naming issues during entity mapping. For example, your entity has a name of EntityName, but for some reason your data table has a name of EntityNames. So in order for Nop to map correctly, you need to use either INameCompatibility interface or NameCompatibilityManager functions to resolve that discrepancy. That also includes column name in the table as well.
A more detail example is this: Let's you want to add a new table. First we define the entity that inherits from BaseEntity (i.e NewEntity : BaseEntity). Then we are going to create the migration for it.
public class NewEntity : BaseEntity
{
public string NewEntityName { get; set; }
public StatusEnum Status { get; set; }
}
[Migration(1, "First migration")]
public class AddNewEntityMigration : Migration
{
private const string TABLE_NAME = "EntityCollection";
public override void Up()
{
Create.Table(TABLE_NAME)
.WithColumn("Id").AsInt32().PrimaryKey().Identity()
.WithColumn("Name").AsString()
.WithColumn("Status").AsInt32();
}
public override void Down()
{
Delete.Table(TABLE_NAME);
}
}
After doing that, you're done as you can use IRepository<NewEntity> right away without doing registration on the DI or db object context (since it has been removed).
However, if your entity information matches with what the migration creates, then that should just work right of the box. But in my example, notice that my table name and one of the column name for the migration are different that the actual entity class. This will cause conflict and requires you to do additional mapping. With the new Nop version, you need to use INameCompatibility like this:
public class PluginDataMappingName : INameCompatibility
{
public Dictionary<Type, string> TableNames => new Dictionary<Type, string>
{
{ typeof(NewEntity), "EntityCollection" } //
}; // Map entity type NewEntity to table EntityCollection
public Dictionary<(Type, string), string> ColumnName => new Dictionary<(Type, string), string>()
{
{ (typeof(NewEntity), "NewEntityName"), "Name" }
}; // Map property NewEntityName of entity type NewEntity with the column name 'Name'
}
Now what about the enum StatusEnum that I have above? What if I want to map it to different type in the database? In order to do that, you would have to include a NopEntityBuilder mapping class similar to the previous NopEntityTypeConfiguration.
public class NewEntityMappingBuilder : NopEntityBuilder<NewEntity>
{
public override void MapEntity(CreateTableExpressionBuilder table)
{
table.WithColumn(NameCompatibilityManager.GetColumnName(typeof(NewEntity), nameof(NewEntity.Status))).AsInt32(); // Map enum to database integer type
}
}
If you want to dig into the Nop codebase to know how to manage those things, I suggest start with MigrationManager.cs and walk backward.
As for linq2db document, yes that is so minimal but I believe you probably do not need to dig into that to develop your plugin since Nop abstract those layers within the codebase. So basically what you have done with previous version of Nop for repository pattern should just work the same, only slight different on the configuration part.