dotnet / interactive

.NET Interactive combines the power of .NET with many other languages to create notebooks, REPLs, and embedded coding experiences. Share code, explore data, write, and learn across your apps in ways you couldn't before.
MIT License
2.8k stars 374 forks source link

Add the option to select the tables/schemas used by --create-dbcontext #3516

Open chrisevans9629 opened 2 months ago

chrisevans9629 commented 2 months ago

Is your feature request related to a problem? Please describe. I have a large database where some tables don't work with the scaffolding. Namely, I get the error message: System.InvalidOperationException: The key {'Id'} cannot be added to keyless type 'Table (Dictionary<string, object>)'.

Describe the solution you'd like I would like an option to enter the tables and schemas like so: #!connect mssql --create-dbcontext --tables User,Order --schemas dbo --kernel-name name connection

Describe alternatives you've considered The only workaround I see is not using this feature and building the DbContext from scratch, or taking the following code and copying/pasting the output into the notebook, which is very ugly:


var services = new ServiceCollection();
services.AddEntityFrameworkDesignTimeServices();
var providerAssembly = Assembly.Load("Microsoft.EntityFrameworkCore.SqlServer");
var providerServicesAttribute = providerAssembly.GetCustomAttribute<DesignTimeProviderServicesAttribute>();
var providerServicesType = providerAssembly.GetType(providerServicesAttribute.TypeName);
var providerServices = (IDesignTimeServices)Activator.CreateInstance(providerServicesType);
providerServices.ConfigureDesignTimeServices(services);

var serviceProvider = services.BuildServiceProvider();
var scaffolder = serviceProvider.GetService<IReverseEngineerScaffolder>();

var model = scaffolder.ScaffoldModel(
    connection,
    new DatabaseModelFactoryOptions(new []{"dbo.Order", "dbo.User"}, new string[0]),
    new ModelReverseEngineerOptions(),
    new ModelCodeGenerationOptions()
    {
        ContextName = "TestContext",
        ModelNamespace = "TestFiles",

    });

model.Display();

var code = @"using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;";

foreach (var file in  new[] { model.ContextFile.Code }.Concat(model.AdditionalFiles.Select(f => f.Code)))
{
    var namespaceToFind = "namespace TestFiles;";
    var headerSize = file.LastIndexOf(namespaceToFind)  + namespaceToFind.Length;
    var fileCode = file
        // remove namespaces, which don't compile in Roslyn scripting
        .Substring(headerSize).Trim();

    code += fileCode;
}

code