使用Roslyn创建一个EF CodeFirst DbContext [英] Creating an EF CodeFirst DbContext using Roslyn

查看:306
本文介绍了使用Roslyn创建一个EF CodeFirst DbContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我正在尝试生成一个非常基本的EF使用Roslyn CTP的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上下文:DbContext {
public DbSet< Car> Cars {get; set;}
}

new Context();
,session);

t.Execute();

执行时,我得到以下异常



例外:


类型提交#0 + Car未映射。通过使用Ignore方法或NotMappedAttribute数据注释来检查类型是否未被明确排除。验证类型是否被定义为类,不是原始的,嵌套的或通用的,并且不会从EntityObject继承。


可能的问题的列表,我猜猜Roslyn正在做一个嵌套的类作为代码的一部分。这是有道理的,否则新的Context();调用需要被包装成某种类的类/方法。我可以发出一个程序集,这将确认上面的内容,但可能没有任何关于如何正确写入的线索。



我也下了语法的路线。 ClassDeclaration,但是结束了几百行代码只是为了使一个类具有1个属性,没有明显的方式如何实例化该类。



问题



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

解决方案

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

  var classCode = @
using System.Data.Entity;

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

public class上下文: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& .Location),// System.Data
new AssemblyFileReference(typeof(DbContext).Assembly.Location)// EntityFramework

.AddSyntaxTrees(syntaxTree);

var dllPath =car.dll;
使用(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);


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)?

解决方案

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);

这篇关于使用Roslyn创建一个EF CodeFirst DbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆