Skip to content

what is the best way to add our own namespace while generating the model via Scaffolding #30332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
archanasoni opened this issue Feb 24, 2023 · 15 comments · Fixed by #31573
Closed

Comments

@archanasoni
Copy link

archanasoni commented Feb 24, 2023

Hi,

We've requierment to add using statement :
using IBM.EntityFrameworkCore

Above statement has to be added while generating the Context class via scaffolding. Till .NET 6 we implemented CSharpDbContextGenerator and added in our service, but from .NET7 we see it is part of .tt file which we are not much familior..
how can we achieve the same result now ?

public override string WriteCode(
                    IModel model,
                    string contextName,
                    string connectionString,
                    string? contextNamespace,
                    string? modelNamespace,
                    bool useDataAnnotations,
                    bool useNullableReferenceTypes,                   
                    bool suppressConnectionStringWarning,
         bool suppressOnConfiguring)
        {
            Check.NotNull(model, nameof(model));
#pragma warning disable EF1001 // Internal EF Core API usage.
            _sb = new IndentedStringBuilder();
            _sb.AppendLine("using IBM.EntityFrameworkCore;");
            //_sb.AppendLine("using IBM.EntityFrameworkCore.Storage.Internal;");
            return _sb.AppendLines(base.WriteCode(model, contextName, connectionString, contextNamespace, modelNamespace, useDataAnnotations, useNullableReferenceTypes, suppressConnectionStringWarning, suppressOnConfiguring)).ToString();
#pragma warning restore EF1001 // Internal EF Core API usage.
        }
@ajcvickers
Copy link
Contributor

@archanasoni Typically, the appropriate namespaces are added based on the types in the generated code. What is the case where this is not happening?

@archanasoni
Copy link
Author

archanasoni commented Feb 27, 2023

@ajcvickers, UseDb2 and IBMDBServerType.LUW require namespace IBM.EntityFrameworkCore

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseDb2("Connection string", 
                p => p.SetServerInfo(IBMDBServerType.LUW));
        }

another example is:

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<NET7TAB1>(entity =>
            {
                entity.HasKey(e => e.ID)
                        .ForDb2IsClustered(false);
            });
        }

@roji
Copy link
Member

roji commented Feb 27, 2023

@archanasoni the UseDB2 method should be on an extension class in the Microsoft.EntityFrameworkCore, much like how UseSQLServer is. This way the method "lights up" for users automatically, without them having to explicit use an IBM-specific namespace.

@archanasoni
Copy link
Author

Thanks @roji from the beginning we have this method and others in IBM specific namespace. For some reasons we do not wish to change.. Could you help how we can add IBM Specific namespace during the model generation ?

@roji
Copy link
Member

roji commented Feb 27, 2023

Since scaffolding switched to using templates in EF 7.0, there's no longer an easy way for a provider to add arbitrary namespaces; users can easily modify the templates in any way they want (that was the point of this feature), but providers cannot.

Note that CSharpDbContextGenerator was internal in 6.0 and below; you should really try to avoid accessing/overriding internal EF APIs so that this kind of breakage doesn't happen. If you finding yourself needing to do something with an internal API, you should signal this to us so we can provide guidance on an alternative implementation, or possibly change things within EF in order to accommodate your needs.

Concretely, we may want to add a a template parameter allowing extra namespaces to be passed; CSharpModelGenerator is still internal, so that still wouldn't be sufficient as a 1st-class way for a provider to inject additional namespaces. /cc @bricelam @ajcvickers

In the meantime, if you don't want to change the namespace of your extension methods, I think you'll have to instruct your users to edit their templates to add the namespace, as per the docs.

@archanasoni
Copy link
Author

archanasoni commented Feb 28, 2023

Thanks @roji but this is a breaking change for us. We implemented internal class by going through some blog from MS but unfortunately, we are unable to find that blog now.
We may instruct our user to customize T4 for a time being.. but I'm wondering for a solution where we (provider) can add our own namespaces... and when the solution will be available.. ?
Is it possible to inherit this template and then do something to add our own namespace... ?

@roji
Copy link
Member

roji commented Feb 28, 2023

@archanasoni we'll discuss this internally and post back here.

FWIW note that there's an analyzer that generates warnings whenever you use an internal EF API (e.g. anything in Internal namespaces), precisely to avoid people accidentally using it. I hope you're seeing those warnings and taking them into account.

@bricelam
Copy link
Contributor

bricelam commented Feb 28, 2023

If you return a MethodCallCodeFragment with a MethodInfo from ProviderCodeGenerator.GenerateUseProvider(), we should generate the using for it... (if not, that's an EF bug.) Are you using the string overload instead?

@archanasoni
Copy link
Author

archanasoni commented Mar 1, 2023

Thanks @bricelam , we had string version that we've changed to MethodInfo now but still we don't see namespace is being generated..

//here MethoInfo is exactly same what we have for SQL Server
 private static readonly MethodInfo UseDb2MethodInfo
        = typeof(Db2DbContextOptionsExtensions).GetRuntimeMethod(
            nameof(Db2DbContextOptionsExtensions.UseDb2),
            new[] { typeof(DbContextOptionsBuilder), typeof(string), typeof(Action<Db2DbContextOptionsBuilder>) })!;


public override MethodCallCodeFragment GenerateUseProvider(
            string connectionString,
            MethodCallCodeFragment? providerOptions)
            => new (UseDb2MethodInfo,
                providerOptions == null
                    ? new object[] { connectionString }
                    : new object[] { connectionString, new NestedClosureCodeFragment("x", providerOptions) });  

@bricelam bricelam self-assigned this Mar 1, 2023
@ajcvickers ajcvickers added this to the 8.0.0 milestone Mar 2, 2023
@bricelam bricelam removed this from the 8.0.0 milestone May 30, 2023
@ajcvickers ajcvickers added this to the 8.0.0 milestone May 31, 2023
@ajcvickers ajcvickers modified the milestones: 8.0.0, Backlog Jun 29, 2023
@bricelam bricelam removed their assignment Jul 8, 2023
@archanasoni
Copy link
Author

@bricelam , @ajcvickers May we know status of this issue ? Will it be fixed in .NET8 ?

@ajcvickers
Copy link
Contributor

@archanasoni Unfortunately, this issue has been postponed and will not ship in EF Core 8.

@archanasoni
Copy link
Author

@ajcvickers it's really important for us to have fix for this.. is there a way which we can implement and fix it by our own in .NET 8 now ?

@ajcvickers
Copy link
Contributor

@archanasoni The best thing to do is use the recommended pattern for scaffolding like the other database providers do. Anything else, even this fix, is just a band aid over the real issue.

@bricelam bricelam self-assigned this Aug 28, 2023
bricelam added a commit to bricelam/efcore that referenced this issue Aug 28, 2023
@bricelam bricelam modified the milestones: Backlog, 8.0.0 Aug 28, 2023
@bricelam bricelam modified the milestones: 8.0.0, 8.0.0-rc2 Aug 29, 2023
@bricelam
Copy link
Contributor

Fixed for 8.0.0-rc2. Using the MethodInfo overloads should now generate the usings.

@ajcvickers ajcvickers modified the milestones: 8.0.0-rc2, 8.0.0 Nov 14, 2023
@archanasoni
Copy link
Author

archanasoni commented Dec 11, 2023

it's fixed in version 8.0.0 Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants