问题
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