GilShalit
GilShalit

Reputation: 6463

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

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!

Upvotes: 116

Views: 90581

Answers (6)

In EF or EF Core, the Column Order attribute is not supported for specifying key order, so the best practice is to configure composite keys in the OnModelCreating method of your DbContext.

public class MyEntity
{
    public int MyFirstKeyProperty { get; set; }

    public int MySecondKeyProperty { get; set; }

    public string MyThirdKeyProperty { get; set; }

    // Other properties
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>()
        .HasKey(e => new { e.MyFirstKeyProperty, e.MySecondKeyProperty, e.MyThirdKeyProperty });

    base.OnModelCreating(modelBuilder);
}

Upvotes: 1

kara
kara

Reputation: 3455

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.

Upvotes: 15

Slauma
Slauma

Reputation: 177133

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.

Upvotes: 172

WACS kumara
WACS kumara

Reputation: 11

Use as a anonymous object:

modelBuilder.Entity<UserExamAttemptQuestion>().ToTable("Users").HasKey(o => new { o.UserId, o.Username }); 

Upvotes: 1

Daniele Armanasco
Daniele Armanasco

Reputation: 7451

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());
    }
}

Upvotes: 13

Morteza Manavi
Morteza Manavi

Reputation: 33206

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 
        });
    }
}

Upvotes: 75

Related Questions