Skip to content

How to specify PK

Mogens Heller Grabe edited this page Oct 11, 2021 · 5 revisions

By convention, if a property is named Id it will be considered PK of the table and will be used to identify each row when upserting.

For example, this type

class SomeDataRow
{
    public SomeDataRow(int id, decimal number, string text)
    {
        Id = id;
        Number = number;
        Text = text;
    }

    public int Id { get; }
    public decimal Number { get; }
    public string Text { get; }
}

will correspond to the following table schema

CREATE TABLE [dbo].[SomeDataRow] (
    [Id] [int] NOT NULL,
    [Number] [decimal](18, 0) NULL,
    [Text] [nvarchar](256) NULL,
    PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )
)

👍

Selecting another property as the ID

If you don't want to have a property named Id on your class, you can specify another ID by decorating a property with the [DebaserKey] attribute, e.g. like so:

class Person
{
    public Person(string ssn, string fullName)
    {
        Ssn = ssn;
        FullName = fullName;
    }

    [DebaserKey]
    public string Ssn { get; }

    public string FullName { get; }
}

which will result in this table schema:

CREATE TABLE [dbo].[Person] (
    [Ssn] [nvarchar](256) NOT NULL,
    [FullName] [nvarchar](256) NULL,
    PRIMARY KEY CLUSTERED 
    (
        [Ssn] ASC
    )
)

which is probably what you expected. 🔑

Using multiple properties to identify each row

If some cases you want multiple properties in combination to identify each row. While you could accomplish this by concatenating a string or hacking it in other ways, you could also just add the [DebaserKey] attribute multiple times, e.g. like this:

class TenantPerson
{
    public TenantPerson(string tenantId, string ssn, string fullName)
    {
        TenantId = tenantId;
        Ssn = ssn;
        FullName = fullName;
    }

    [DebaserKey]
    public string TenantId { get; }

    [DebaserKey]
    public string Ssn { get; }

    public string FullName { get; }
}

which is a version of the Person model shown before, only scoped by a TenantId so that tenants can have records for the same SSN without interfering. It will result in this table schema:

CREATE TABLE [dbo].[TenantPerson] (
    [TenantId] [nvarchar](256) NOT NULL,
    [Ssn] [nvarchar](256) NOT NULL,
    [FullName] [nvarchar](256) NULL,
    PRIMARY KEY CLUSTERED 
    (
        [TenantId] ASC,
        [Ssn] ASC
    )
)

which does not really come as a surprise at this point. 🔑 🔑 🥇