gpt4 book ai didi

entity-framework - 代码优先的 DbContext Generator T4 模板

转载 作者:行者123 更新时间:2023-12-04 08:32:26 26 4
gpt4 key购买 nike

数据库优先(和模型优先)方法有这个很好的 DbContext Generator 脚手架文件来生成上下文和模型;模型.上下文.tt + 模型.tt

由于它们有内置的辅助方法来检索导航属性,因此将它们用于其他目的也非常方便,例如创建 Controller 、 View 等。ASP.NET Scaffolding 也做类似的工作,但在这种情况下,脚手架需要按模型调用,相比之下,这些 T4 文件一次生成所有文件。

但是,他们只使用“edmx”文件作为输入。是否可以将它们用于代码优先方法?

Entity Framework 6.1 版

最佳答案

这是一个工作示例 - 2018 年 6 月 5 日更新:
https://github.com/coni2k/DbContextGeneratorWithCodeFirst

  • Visual Studio 2017
  • 目标框架 4.6.1
  • Entity Framework 6.2.0


  • 有几个步骤可以实现这一点。

    1. 找到并复制 EF6.Utility.CS.ttinclude 到你的项目

    在T4文件(Model.Context.tt + Model.tt)中, inputFile变量(edmx文件)在两个位置使用;
    const string inputFile = @"QAModel.edmx";
    //var textTransform ...
    //var code ...
    //var ef ...
    //var typeMapper ...
    //var fileManager ...
    var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile);
    //var codeStringGenerator ...

    if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile))
    VerifyCaseInsensitiveTypeUniqueness 是一种验证方法, inputFile 用作错误的源位置。重要的是 EdmMetadataLoader ,它来自文件开头定义的 EF6.Utility.CS.ttinclude 文件;
    <#@ include file="EF6.Utility.CS.ttinclude"#><#@ 

    由于该文件需要修改,找到该文件并复制到您的项目文件夹中。就我而言,它位于此文件夹下;
    %ProgramFiles(x86)%\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes\

    如您所见,这是一个可选步骤。我们可以修改原始文件,但使用副本并保持原始文件完整更安全。

    2.修改ttinclude文件

    在include文件中,有3种使用edmx文件的方法。
    public IEnumerable<GlobalItem> CreateEdmItemCollection(string sourcePath)

    public XElement LoadRootElement(string sourcePath)

    private void ProcessErrors(IEnumerable<EdmSchemaError> errors, string sourceFilePath)

    重要的是读取xml文件的 LoadRootElement方法。我们可以从 Code First DbContext 创建一个内存流,并让它从这个流中读取数据,而不是传递物理 xml。

    一种。将这两个方法添加到包含文件中;
    public IEnumerable<GlobalItem> CreateEdmItemCollection(DbContext dbContext)
    {
    ArgumentNotNull(dbContext, "dbContext");

    var schemaElement = LoadRootElement(dbContext);
    if (schemaElement != null)
    {
    using (var reader = schemaElement.CreateReader())
    {
    IList<EdmSchemaError> errors;
    var itemCollection = EdmItemCollection.Create(new[] { reader }, null, out errors);

    ProcessErrors(errors, dbContext.Database.Connection.ConnectionString);

    return itemCollection ?? new EdmItemCollection();
    }
    }
    return new EdmItemCollection();
    }

    public XElement LoadRootElement(DbContext dbContext)
    {
    ArgumentNotNull(dbContext, "dbContext");

    XElement root;

    using (var stream = new MemoryStream())
    {
    using (var writer = XmlWriter.Create(stream))
    {
    EdmxWriter.WriteEdmx(dbContext, writer);
    }
    stream.Position = 0;

    root = XElement.Load(stream, LoadOptions.SetBaseUri | LoadOptions.SetLineInfo);
    root = root.Elements()
    .Where(e => e.Name.LocalName == "Runtime")
    .Elements()
    .Where(e => e.Name.LocalName == "ConceptualModels")
    .Elements()
    .Where(e => e.Name.LocalName == "Schema")
    .FirstOrDefault()
    ?? root;
    }

    return root;
    }

    现在我们在包含文件中使用 DbContext,这需要包含 System.Data.Entity 库。

    湾在文件的开头添加这三行;
    //<#@ assembly name="%VS120COMNTOOLS%..\IDE\Microsoft.Data.Entity.Design.dll" #>
    <#@ assembly name="System.Data.Entity" #>
    <#@ import namespace="System.Data.Entity" #>
    <#@ import namespace="System.Data.Entity.Infrastructure" #>
    //<#@ import namespace="System" #>

    3. 通过添加新的构造函数来修改 DbContext 类

    由于 T4 文件有自己的域,因此无法使用项目的 web/app.config 文件中的连接字符串来初始化 DbContext。最简单的解决方法是使用显式连接字符串对其进行初始化。

    通过添加将连接字符串作为参数的新构造函数来修改您的 DBContext 类。
    public QAContext(string nameOrConnectionString)
    : base(nameOrConnectionString)
    {
    }

    4.修改T4文件

    现在 T4 已准备好传递 Code First DbContext 实例。相应地更新文件。

    一种。为了能够访问和实例化它,将 DbContext 类库作为程序集引用添加到 T4 文件的开头;
    //<#@ template language="C#" ...
    <#@ assembly name="$(SolutionDir)DbContextGeneratorWithCodeFirst\bin\Debug\DbContextGeneratorWithCodeFirst.dll"#>
    //<#@ include file="EF6 ...

    湾用 inputFile 替换 connectionString 变量
    const string connectionString = @"Server=(LocalDb)\v11.0;Database=QADb;Integrated Security=True;MultipleActiveResultSets=True";
    //var textTransform ...

    C。更新 CreateEdmItemCollection
    //var   fileManager ...
    IEnumerable<GlobalItem> itemCollection;
    using (var dbContext = new DbContextGeneratorWithCodeFirst.QAContext(connectionString))
    {
    itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(dbContext);

    if (itemCollection == null)
    {
    return string.Empty;
    }
    }
    //var codeStringGenerator ...

    d.使用 VerifyCaseInsensitiveTypeUniqueness 参数更新 connectionString 方法
    if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), connectionString))

    现在可以使用了。您可以根据需要修改文件的其余部分,以基于您的 Code First 模型创建您想要的任何文件,如 html、javascript、razor 等。

    这是一项工作,绝对可以改进。比如include文件可以以 DbContext类型为参数,实例化,判断是Code First还是Database First,然后继续处理。或者找到 web/app.config 文件并从那里读取连接字符串。不过刚开始应该够了。

    关于entity-framework - 代码优先的 DbContext Generator T4 模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23347093/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com