【问题标题】:Prevent T4 template from deleting existing files防止 T4 模板删除现有文件
【发布时间】:2011-05-09 17:29:31
【问题描述】:

我想为我的 edmx-model 中的每个实体创建一个名为 {0}Validator.cs 的单独类文件(现在不关心它的内容)。

这似乎可行,但我无法阻止我的 T4 模板首先删除我的所有文件。我怎样才能摆脱这种行为?

我发现如果我调用 fileManager.Process(true),我的 validator.tt 文件下的所有文件都将被重新创建(我不希望这样)。

有什么想法吗? 谢谢!

<#@ template language="C#" debug="false" hostspecific="true"#>
//<#@ include file="EF.Utility.CS.ttinclude"#>
<#@output extension=".cs"#>

<#
CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);

string inputFile =@"ServicesEntities.edmx";
EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);
string namespaceName = code.VsNamespaceSuggestion();

EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);

// for test purposes only...
fileManager.Process(true);

// for each entity, create a xxxValidator.cs file

foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
{
     string fileName = entity.Name + "Validator.cs";
     string filePath = this.Host.TemplateFile.Substring(0,this.Host.TemplateFile.LastIndexOf(@"\")); 
     filePath = filePath + @"\" + fileName;

     if(!File.Exists(filePath)) 
     {
          fileManager.StartNewFile(filePath);

#>
// the content of the validator class
public partial class <#=code.Escape(entity)#>
{
    public bool ValidateModel()
    {
    // enter checkmethods here!!! again
    return true;
    }
}
<#          
    }           
}

fileManager.Process(true);

#>

【问题讨论】:

    标签: entity-framework t4


    【解决方案1】:

    我的情况完全一样。我想为数据注释生成伙伴类。我不想将数据放入 edmx 文件并更改我的模板以根据 edmx 数据添加正确的注释。那将花费太长时间。最简单的解决方案是生成一个伙伴类并将其设置为不会每次都重新生成。在这种情况下,效率比应始终重新生成 T4 类的约定更重要。

    Dane Morgridge 想出了一个聪明的方法来做到这一点。他检查文件是否已经存在。如果是,他将其读入并按原样写回。如果不是,他会渲染他的模板。查看 DbContext Templates\IRepository.tt。 https://github.com/danemorgridge/efrepo

    以下是相关部分。

    string OutputFile(string filename)
    {
        using(StreamReader sr = new StreamReader(Path.Combine(GetCurrentDirectory(),filename)))
        {
            string contents = sr.ReadToEnd();
            return contents;
        }
    }
    
    if(!DoesFileExist(entity.Name + "Repository.cs"))
    {
        fileManager.StartNewFile(entity.Name + "Repository.cs");
    }
    else
    {
        fileManager.StartNewFile(entity.Name + "Repository.cs");
        this.Write(OutputFile(entity.Name + "Repository.cs"));
    }
    

    【讨论】:

      【解决方案2】:

      有点晚了,但物有所值...如果您使用的是 T4Toolbox,您可以告诉引擎在触发生成并且文件已经存在时不要删除生成的文件:

      template.Output.PreserveExistingFile = true;
      

      http://t4toolbox.codeplex.com

      【讨论】:

      • 正是我想要的
      【解决方案3】:

      不,你不能。 T4 模板每次被触发并执行代码时都会生成代码。在此之前,所有文件都会被删除。但是你有什么问题呢?您的自定义代码应放置在部分中,因此其他部分获取是否重新生成无关紧要。

      【讨论】:

      • 感谢您的回答。当然,自定义类在单独的部分类中,但每次运行 t4 模板时都应创建部分类,如果用户已更新 edmx(添加了新表),现有类应保持不变,并且应为新添加的数据库表生成新的验证器类(而不是由用户手工制作)。这就是我想要的,但也许为此目的提供一个 sn-p 或模板会花费更少的时间;-)。谢谢!
      • 是的,这似乎是满足您需求的更好解决方案,因为您希望能够告诉 T4 保留已生成的文件。
      • 嗨,Sra,我想我会以 sn-p/模板的方式来做这件事——我没有时间放松 :-)。感谢您的回答!
      【解决方案4】:

      重新创建文件有什么问题? T4 生成代码,您不应触摸生成的代码。如果您使用 T4 模板只是为了创建具有某些名称的文件,那么您使用它是错误的。您可以创建真正的 T4 模板,它也会生成文件内容,或者您​​不应该使用 T4 模板并手动创建文件。

      【讨论】:

      • 您好,感谢您的回答 - 我会记住这一点。娱乐没有什么问题,除了:我不想要这个。如果你不关心文件的内容(当然,文件会得到一些生成的逻辑),对我来说挑战不仅仅是创建一些文件,挑战是:我可以防止每次重新生成文件如果我不想要这个?我想我最好使用 sn-ps 和模板,而 MAYBE T4 是 - 你可能是对的 - 不是用于这个特定目的的正确工具。谢谢!
      【解决方案5】:

      对于创建元数据、服务和 ViewModel 类(我希望能够修改)的 T4 模板,我希望能够将新模板与现有模板合并,以及为新实体创建任何新模板,所以我在调用 fileManager.StartNewFile...之前创建了文件 (.BAK) 的备份...

          foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
          {
              var outputPath = Path.GetDirectoryName(Host.TemplateFile);
              var outputFile = entity.Name + ".ViewModel.cs";
              var fileName = Path.Combine(outputPath, outputFile);
              if (File.Exists(fileName))
              {
                  var newName = fileName + ".BAK";
                  File.Move(fileName, newName);
              }
      
              fileManager.StartNewFile(outputFile);
      

      然后在 fileManager.Process 之后,我使用 SourceGear 的 DiffMerge 合并 .BAK 文件和新文件...

          fileManager.Process();
      
          System.Diagnostics.Process p = new System.Diagnostics.Process();
      
          foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
          {
      
              var outputPath = Path.GetDirectoryName(Host.TemplateFile);
              var outputFile = entity.Name + ".ViewModel.cs";
              var fileName = Path.Combine(outputPath, outputFile);
              var newName = fileName + ".BAK";
              if (File.Exists(newName))
              {
                  String s = String.Format("-m -nosplash \"{0}\" \"{1}\" \"{2}\"", fileName, fileName, newName);
                  p.StartInfo.Arguments = s;
                  p.StartInfo.FileName = "C:\\Program Files (x86)\\SourceGear\\DiffMerge\\DiffMerge.exe";
                  p.StartInfo.Verb = "Open";
                  p.Start();
                  p.WaitForExit();
      
                  File.Delete(newName);
              }
      
          }
      

      效果很好,而且由于 DiffMerge 是一个 GUI 应用程序,我可以在保存之前处理冲突等。

      【讨论】:

        猜你喜欢
        • 2021-06-15
        • 2013-06-05
        • 2011-05-10
        • 2012-08-07
        • 1970-01-01
        • 2019-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多