Creating an EF CodeFirst DbContext using Roslyn

拈花ヽ惹草 提交于 2019-12-04 23:47:29

问题


Just a little idea I'm playing with, not sure if it's viable or has much of a use.

I'm trying to generate a very basic EF Code First database using the Roslyn CTP.

Code:

var scriptEngine = new ScriptEngine(new[] { "System", "System.Core", typeof(DbContext).Assembly.Location });
var session = Roslyn.Scripting.Session.Create();

var t = scriptEngine.CompileSubmission<DbContext>(@"
  using System.Data.Entity;         
  public class Car  {
    public int Id {get; set;}
    public string Name {get;  set; }
  }

  public class Context : DbContext {
    public DbSet<Car> Cars {get; set; }
  }

  new Context();
", session);

t.Execute();

When executed I get the following exception

Exception:

The type 'Submission#0+Car' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive, nested or generic, and does not inherit from EntityObject.

Looking through the list of possible issues, I'm guessing that Roslyn is making a nested class as part of the code gen. This makes sense otherwise the "new Context();" call would need to be wrapped into a class/method of some sort. I could emit an assembly, which would confirm the above but likely wouldn't have any clues on how to write it correctly.

I also went down the route of Syntax.ClassDeclaration, but ended up with a few hundred lines of code just to make a class with 1 property and no obvious way how to instantiate that class.

Question

Is there an easy way to create a class in Roslyn that is publicly accessible (eg not nested in another class)?


回答1:


You can use Roslyn to create actual DLL library that contains your type based on your source code and then use that from your script:

var classCode = @"
using System.Data.Entity;   

public class Car  {
    public int Id { get; set; }
    public string Name { get;  set; }
}

public class Context : DbContext {
    public DbSet<Car> Cars { get; set; }
}";

var syntaxTree = SyntaxTree.ParseCompilationUnit(classCode);

var compilation = Compilation.Create(
    "car",
    new CompilationOptions(assemblyKind: AssemblyKind.DynamicallyLinkedLibrary))
    .AddReferences(
        new AssemblyFileReference(typeof(object).Assembly.Location), // mscorlib
        new AssemblyFileReference(typeof(Uri).Assembly.Location), // System
        new AssemblyFileReference(typeof(IOrderedQueryable<>).Assembly.Location), // System.Data
        new AssemblyFileReference(typeof(DbContext).Assembly.Location) // EntityFramework
    )
    .AddSyntaxTrees(syntaxTree);

var dllPath = "car.dll";
using (var stream = File.OpenWrite(dllPath))
{
    compilation.Emit(stream);
}

var code = @"new Context();";
var scriptEngine = new ScriptEngine(new[] { new FileInfo(dllPath).FullName, "EntityFramework" });

var context = scriptEngine.Execute<DbContext>(code);


来源:https://stackoverflow.com/questions/9146068/creating-an-ef-codefirst-dbcontext-using-roslyn

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!