Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

c# - Net Core: Create Generic Repository Interface Id Mapping for All Tables Auto Code Generation

We just Scaffolded our database, and created Models from Database tables in Entity Framework.

Additionally, we are creating files with Ids which Map to the Primary Key. The purpose of this is to map to our Generic Repository Interface which utilizes Id.

How do I go through all my 200 + models, and create a file similar to file 2 below. I've seen it conducted at previous workplaces. Trying to research. Is there a Visual Studio or Entity framework feature which loops through all models automatically? Currently I am going through each model, and creating the id manually as seen in Generic Id File 2. Willing to implement T4 which implements code generation however other solutions are good.

Scaffolded Files 1:

namespace Datatest
{
    public partial class Property
    {
        public int Property { get; set; }
        public int DocumentId { get; set; }
        public string Address { get; set; }
    }
}

Generic ID File 2:

public partial class Property: IEntity
{
    [NotMapped]
    public int Id { get => PropertyId; set => PropertyId = value; }
}

Sample Generic Base Repository for all tables:

    public T Get(int id)
    {
        return Table.Find(id);
    }
    public async Task<T> GetAsync(int id)
    {
        return await Table.FindAsync(id);
    }
    public T Single(Expression<Func<T, bool>> predicate)
    {
        return All.Single(predicate);
    }
    public async Task<T> SingleAsync(Expression<Func<T, bool>> predicate)
    {
        return await All.SingleAsync(predicate);
    }
    public T FirstOrDefault(int id)
    {
        return All.FirstOrDefault(CreateEqualityExpressionForId(id));
    }

Maybe this resource helps? Trying to make it loop through all my model files now How to create multiple output files from a single T4 template using Tangible Editor?

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".txt" #>
<#
for (Int32 i = 0; i < 10; ++i) {
#>
Content <#= i #>
<#
  // End of file.
  SaveOutput("Content" + i.ToString() + ".cs");
}
#>
<#+
private void SaveOutput(string outputFileName) {
  string templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
  string outputFilePath = Path.Combine(templateDirectory, outputFileName);
  File.WriteAllText(outputFilePath, this.GenerationEnvironment.ToString()); 
  this.GenerationEnvironment.Remove(0, this.GenerationEnvironment.Length);
}
#>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I agree with @Ivan, I wouldn't recommend you this way, but you answered that you need to, so here we go.

You're using EFCore right ? Luckily, EFCore is open-source, so we can dig into the source code and build custom EFCore versions.

A few months ago I had also a specific need with EF Context scaffolding, we also have over 200 tables and needed to put mappings for each table in a separate class, because EF Core, defaults to put all the mapping stuff in the DbContext file and this generated a 10k+ lines of code long DbContext class for us ??.

EntityTypes generation is handled here. Interesting line for you is #109 :

_sb.AppendLine($"public partial class {entityType.Name}");

Here you could just add your Interface this way :

_sb.AppendLine($"public partial class {entityType.Name} : IEntity");

Then we have to implement your interface, on line #113 we have the following code :

using (_sb.Indent())
{
   GenerateConstructor(entityType);
   GenerateProperties(entityType);
   GenerateNavigationProperties(entityType);
}

Just before GenerateProperties(entityType); you can add the following lines to implement interface specification :

_sb.AppendLine("[NotMapped]");
_sb.AppendLine("public int Id { get => PropertyId; set => PropertyId = value; }");
_sb.AppendLine("");

If your really need/want partial classes you could simply write some code to generate another file in the WriteCode method which is called once per table and has all the info needed for this (type name, etc.)

Here is the code for building the project with your custom implementation. After scaffolding your project you can just return to a official EFCore build.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...