in entity framework code first, how to use KeyAttribute on multiple columns
Asked Answered
S

5

113

I'm creating a POCO model to use with entity framework code first CTP5. I'm using the <key()> decoration to make a property map to a PK column. But how can I define a PK on more then one column, and specifically, how can I control order of the columns in the index? Is it a result of the order of properties in the class?

Edit: look at @kara's answer for an updated solution.

Thanks!

Steersman answered 9/2, 2011 at 20:45 Comment(0)
D
169

NOTE: As of 2019 this answer became non-valid for later EntityFramework versions.

You can specify the column order in the attributes, for instance:

public class MyEntity
{
    [Key, Column(Order=0)]
    public int MyFirstKeyProperty { get; set; }

    [Key, Column(Order=1)]
    public int MySecondKeyProperty { get; set; }

    [Key, Column(Order=2)]
    public string MyThirdKeyProperty { get; set; }

    // other properties
}

If you are using the Find method of a DbSet you must take this order for the key parameters into account.

Disqualify answered 9/2, 2011 at 21:20 Comment(1)
InvalidOperationException: Entity type 'XXX' has composite primary key defined with data annotations. To set composite primary key, use fluent API.Washing
C
73

To complete the correct answer submitted by Slauma, you can use the HasKey method to specify an order for composite primary keys as well:

public class User
{        
    public int UserId { get; set; }       
    public string Username { get; set; }        
}        

public class Ctp5Context : DbContext
{
    public DbSet<User> Users { get; set; }        

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().HasKey(u => new 
        { 
            u.UserId, 
            u.Username 
        });
    }
}
Concordia answered 9/2, 2011 at 21:24 Comment(3)
Thanks - both methods do work fine. I prefer the Attributes because I'm generating my classes from code, and attributes are much more concise.Steersman
I personally also add the Propety(x...).HasColumnOrder(0...n) to each of the keyed properties. Is that good, bad, indifferent?Cyn
This answer will work for latest EF-versions.Newfangled
M
12

If, like me, you prefer to use a configuration file you can do that in this way (based on Manavi's example):

public class User
{
    public int UserId { get; set; }
    public string Username { get; set; }
}  

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {
        ToTable("Users");
        HasKey(x => new {x.UserId, x.Username});
    }
}

Obviously you have to add the configuration file to your context:

public class Ctp5Context : DbContext
{
    public DbSet<User> Users { get; set; }        

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.Configurations.Add(new UserConfiguration());
    }
}
Maiden answered 11/4, 2013 at 15:18 Comment(0)
C
8

In EF Core 7.0 a new attribute for classes [PrimaryKey] was introduced.

Example:

[PrimaryKey(nameof(FirstName),nameof(LastName))]
public class Person
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string SomeProperty { get; set; }
}

This way, you don't have to use the fluent-api again.

Cookgeneral answered 25/5, 2023 at 13:23 Comment(1)
Thank you @kara. This question was asked in 2011, referring to ef5 and was consistently popular. It documents the change through ef6 and now efc7, and should be turned into a wiki entry...Steersman
S
0

Use as a anonymous object:

modelBuilder.Entity<UserExamAttemptQuestion>().ToTable("Users").HasKey(o => new { o.UserId, o.Username }); 
Spiky answered 25/2, 2018 at 15:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.