Skip to content

Settings.UsePrivateSetterForComputedColumns

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

Settings.UsePrivateSetterForComputedColumns

Gives computed columns a private set; so your code cannot try to assign a value the database works out for itself.

Type bool
Default true
Applies to EF 6 and EF Core
Databases All. Only has an effect where a database reports computed columns: SQL Server, PostgreSQL, MySQL and Oracle
In Database.tt? Yes

What it does

A computed column is one the database calculates from other columns. You never write to it - SQL Server rejects the attempt - and its value changes on its own whenever the columns it is built from change.

That is awkward for a POCO, because a plain { get; set; } property invites exactly the assignment that will fail. Worse, it fails at SaveChanges() rather than at compile time, so you find out at run time.

When this setting is true, the generator gives those properties a private setter. EF Core can still populate them when it materialises an entity, because it writes through the private setter directly, but your own code cannot. The mistake becomes a compiler error instead of a run-time one.

Example

Every example on this page comes from this table. DisplayLabel is the computed column:

CREATE TABLE dbo.Product
(
    ProductId    int            NOT NULL IDENTITY(1, 1),
    ProductName  nvarchar(100)  NOT NULL,
    UnitPrice    decimal(18, 2) NOT NULL CONSTRAINT DF_Product_UnitPrice DEFAULT ((0)),
    Notes        nvarchar(max)  NULL,
    CategoryId   int            NOT NULL,
    DisplayLabel AS (CONVERT(nvarchar(150), ProductName + ' (' + CONVERT(varchar(20), UnitPrice) + ')')),
    CONSTRAINT PK_Product PRIMARY KEY (ProductId),
    CONSTRAINT FK_Product_Category FOREIGN KEY (CategoryId) REFERENCES dbo.Category (CategoryId)
);

Settings.UsePrivateSetterForComputedColumns = true (default)

    // Product
    public class Product
    {
        public int ProductId { get; set; } // ProductId (Primary key)
        public string ProductName { get; set; } // ProductName (length: 100)
        public decimal UnitPrice { get; set; } // UnitPrice
        public string Notes { get; set; } // Notes
        public int CategoryId { get; set; } // CategoryId
        public string DisplayLabel { get; private set; } // DisplayLabel (length: 150)

        // Foreign keys

        /// <summary>
        /// Parent Category pointed by [Product].([CategoryId]) (FK_Product_Category)
        /// </summary>
        public Category Category { get; set; } // FK_Product_Category

        public Product()
        {
            UnitPrice = 0m;
        }
    }

Settings.UsePrivateSetterForComputedColumns = false

    // Product
    public class Product
    {
        public int ProductId { get; set; } // ProductId (Primary key)
        public string ProductName { get; set; } // ProductName (length: 100)
        public decimal UnitPrice { get; set; } // UnitPrice
        public string Notes { get; set; } // Notes
        public int CategoryId { get; set; } // CategoryId
        public string DisplayLabel { get; set; } // DisplayLabel (length: 150)

        // Foreign keys

        /// <summary>
        /// Parent Category pointed by [Product].([CategoryId]) (FK_Product_Category)
        /// </summary>
        public Category Category { get; set; } // FK_Product_Category

        public Product()
        {
            UnitPrice = 0m;
        }
    }

One line differs: DisplayLabel goes from { get; private set; } to { get; set; }. Everything else, including the entity configuration, is identical - the setting changes the property declaration and nothing else.

Either way the entity configuration marks the column as database-generated, so EF never tries to write it:

builder.Property(x => x.DisplayLabel).HasColumnName(@"DisplayLabel").HasColumnType("nvarchar(150)").IsRequired(false).HasMaxLength(150).ValueGeneratedOnAddOrUpdate();

When to use it

Leave it at true. It is the safer default and it costs nothing.

Set it to false when something outside your control needs to write to the property:

  • Object mappers that use property setters. AutoMapper, Dapper's QueryFirst, and most JSON deserialisers need a public setter. If you map a DTO onto an entity and the mapper hits the computed property, it will either throw or silently skip the value depending on the library.
  • System.Text.Json deserialisation ignores properties without a public setter, so a round-trip through JSON quietly loses the value.
  • Test fixtures that build an entity by hand and want to set the computed value to something predictable.

Gotchas

This is about the C# property, not the database. Setting it to false does not make the column writable. The database still rejects a write to a computed column, and EF still will not attempt one, because the configuration marks it ValueGeneratedOnAddOrUpdate() regardless.

Settings.UsePropertyInitialisers does not interact with it. Computed columns never get an initialiser, because there is no default to initialise them to.

A private setter needs a partial class if you want to widen it later. You cannot add a public setter to a generated property from another file. Either turn this setting off or expose a separate writable property in your own partial class.

See also

Clone this wiki locally