使用Roslyn创建EF CodeFirst DbContext

Bet*_*tty 5 ef-code-first roslyn

只是一个小小的想法,我正在玩,不知道它是否可行或有多大用处.

我正在尝试使用Roslyn CTP生成一个非常基本的EF Code First数据库.

码:

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();
Run Code Online (Sandbox Code Playgroud)

执行时,我得到以下异常

例外:

未映射"提交#0 + Car"类型.使用Ignore方法或NotMappedAttribute数据批注检查未明确排除类型.验证类型是否已定义为类,不是原始类,嵌套类还是通用类,并且不从EntityObject继承.

通过查看可能出现的问题列表,我猜测Roslyn正在将嵌套类作为代码生成的一部分.这有意义,否则"新的Context();" 调用需要包装到某种类/方法中.我可以发出一个程序集,这将确认上述内容,但可能没有任何关于如何正确编写它的线索.

我也走了Syntax.ClassDeclaration的路线,但最终得到了几百行代码,只是为了创建一个具有1个属性的类,并且没有明显的方法来实例化该类.

是否有一种简单的方法可以在Roslyn中创建一个可公开访问的类(例如,不嵌套在另一个类中)?

svi*_*ick 5

您可以使用Roslyn根据源代码创建包含类型的实际DLL库,然后使用脚本中的类型:

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);
Run Code Online (Sandbox Code Playgroud)

  • 是的,似乎不可能.我用动态装配尝试了它,它也没用. (2认同)