Skip to content

Settings.WriteInsideClassBody

Simon Hughes edited this page Aug 30, 2026 · 1 revision

Settings.WriteInsideClassBody

Injects a block of your own C# into the body of each generated entity class.

Type Func<Table, string> - return the code, or string.Empty for none
Default Returns string.Empty
Applies to EF 6 and EF Core
Databases All
In Database.tt? Yes, with a commented-out example

What it does

Returns text that is written verbatim inside the class, before the properties. It is a text hook, not a model hook: the generator does not parse or validate what you return.

Reach for it when the same boilerplate belongs on many entities and a partial class per entity would be worse. INotifyPropertyChanged is the canonical case - you need the event and the raiser on every class, and writing one partial file per table is not a serious option.

Example

Settings.WriteInsideClassBody = delegate(Table t)
{
    if (t.NameHumanCase != "Category")
        return string.Empty;

    return
        "        public override string ToString()" + Environment.NewLine +
        "        {" + Environment.NewLine +
        "            return CategoryName;" + Environment.NewLine +
        "        }" + Environment.NewLine;
};
    // Category
    public class Category
    {
            public override string ToString()
            {
                return CategoryName;
            }
        public int CategoryId { get; set; } // CategoryId (Primary key)
        public string CategoryName { get; set; } // CategoryName (length: 50)

        // Reverse navigation

        /// <summary>
        /// Child Products where [Product].[CategoryId] point to this entity (FK_Product_Category)
        /// </summary>
        public ICollection<Product> Products { get; set; } // Product.FK_Product_Category

        public Category()
        {
            Products = new List<Product>();
        }
    }

Note where it landed: at the top of the class, before the properties, and with the indentation exactly as you supplied it. The generator does not re-indent your text, which is why the sample above is indented one level less than the properties around it - the eight leading spaces in the string are what you get.

When to use it

INotifyPropertyChanged on every entity, without a partial file per table:

Settings.WriteInsideClassBody = t =>
    "        public event PropertyChangedEventHandler PropertyChanged;" + Environment.NewLine +
    "        protected virtual void OnPropertyChanged([CallerMemberName] string name = null)" + Environment.NewLine +
    "        {" + Environment.NewLine +
    "            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));" + Environment.NewLine +
    "        }" + Environment.NewLine;

Add System.ComponentModel and System.Runtime.CompilerServices to Settings.AdditionalNamespaces, and see How to implement OnPropertyChanged for the full recipe.

A ToString() chosen by what the table has. Useful in debugging and in dropdown binding:

Settings.WriteInsideClassBody = t =>
{
    var name = t.Columns.FirstOrDefault(c => c.NameHumanCase == "Name" || c.NameHumanCase.EndsWith("Name"));
    return name == null ? string.Empty :
        "        public override string ToString() => " + name.NameHumanCase + ";" + Environment.NewLine;
};

Interface members an interface you attached in Settings.UpdateTable requires.

Gotchas

Prefer a partial class where you can. If the code applies to one or two entities, set Settings.EntityClassesModifiers = "public partial" and write a normal .cs file. It is real code with real tooling - IntelliSense, refactoring, the compiler pointing at the right line. Strings in a .tt have none of that. This callback earns its place when the code has to go on many entities.

You own the indentation and the line endings. Nothing is re-indented, and forgetting a trailing newline runs your last line into the first property.

Syntax errors surface in the generated file, with a line number that means nothing in your .tt. Write the code in a real .cs file first, get it compiling, then wrap it in strings.

It runs for views too. Check t.IsView if that matters.

Verbatim strings do not help as much as you expect. A C# verbatim string in a .tt cannot contain the #> sequence, and quoting inside it needs doubling. Concatenating normal strings with Environment.NewLine is uglier but survives contact with T4.

See also

Clone this wiki locally