Prevent T4 template from deleting existing files
I want to create for each entity in my edmx-model a separate class file called {0}Validator.cs (do not care about its content by now).
This seems to work, but I can't work it out to prevent my T4 template from deleting all my files first. How can I get rid of this behavior?
What I found out is that if I call fileManager.Process(true), all the files under my validator.tt file will be recreated (and I don't want this).
Any ideas please? Thanks!
<#@ 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);
#>
开发者_开发知识库
I am in the exact same situation. I want to generate buddy classes for data annotation. I don't want to put data into the edmx file and alter my templates to add the correct annotations based on the edmx data. That would take too long. The easiest solution is to generate a buddy class and set it so it doesn't regenerate every time. In this case efficiency is more important than the convention that T4 classes should always be regenerated.
Dane Morgridge figured out a clever way to do this. He checks to see if the file already exists. If it does he reads it in and writes it back out the way it was. If it doesn't he renders his template. Check out DbContext Templates\IRepository.tt. https://github.com/danemorgridge/efrepo
Here are the relevant sections.
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"));
}
A bit late, but for what it's worth... If your are using T4Toolbox you can tell the engine not to delete generated files if a generation is triggered and the file already exists:
template.Output.PreserveExistingFile = true;
http://t4toolbox.codeplex.com
No, you can't. The T4 Templates generates the code each time they are triggered and perform the code. And before that all files get deleted. But what is your problem with that? You custom code should be placed in partials so it doesn't matter if the the other partial get's regenerated.
What's wrong with recreating files? T4 generates the code and you should not touch generated code. If you use T4 template just to create files with some names you are using it wrong. You can either create real T4 template which will generate content of your file as well or you should not use T4 template and create files manually.
For T4 templates that create Metadata, Service and ViewModel classes (which I want to be able to modify), I wanted the ability to merge the new templates with the existing ones, as well as create any new ones for new Entities, so I create a backup of the file (.BAK) before calling fileManager.StartNewFile...
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);
and then after fileManager.Process I merge the .BAK file and the new one using SourceGear's DiffMerge...
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);
}
}
Works pretty well, and since DiffMerge is a GUI app, I can handle conflicts, etc. before saving.
精彩评论