Use the ColumnAttribute or the HasKey method to specify an order for composite primary keys

trailmax picture trailmax · Aug 11, 2012 · Viewed 36.7k times · Source

I'm trying to use composite primary key on 2 objects with parent-child relationship. Whenever I try to create a new migration, I get an error:

Unable to determine composite primary key ordering for type 'Models.UserProjectRole'. Use the ColumnAttribute or the HasKey method to specify an order for composite primary keys.

As per error suggests, I do add annotation Column (Order = X) but the error still there and does not go away, unless I leave only one field with Key annotation. Here is my object that it trips off:

public class UserProjectRole
{
    [Key, Column(Order = 0),DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid UserProjectRoleID { get; set; }

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

    [ForeignKey("ProjectID")]
    public Project Project { get; set; }

    public Guid AppUserGuid { get; set; }

    // followed by a number of unrelated String fields.
 }

Here is Project class:

public class Project: Base
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid ProjectID { get; set; }

    public virtual ICollection<UserProjectRole> UserRoles { get; set; }

    // followed by a number of unrelated String fields.

}

Here is part of my DBContext:

public class SiteContext : DbContext
{

    public DbSet<Project> Projects { get; set; }

    public DbSet<UserProjectRole> UserProjectRoles { get; set; }
}

I'm in VisualStudio 2012 with EF 4.3.1

I have been banging my head against this for a while now and all the forum and SO answers suggest to add Column Order annotation that I already have. Am I missing something obvious???

Thank you for reading this far -)

Answer

trailmax picture trailmax · Aug 11, 2012

It took a lot of fiddling about and testing different things. I was clueless until I decided to make a new vanilla project with the similar data structure from scratch. And when I installed EntityFramework from NuGet, I was shown a message:

Known Issues with Entity Framework 4.x and .NET Framework 4.5

Entity Framework 4.1 thru 4.3 included additional data annotations in the System.ComponentModel.DataAnnotations namespace in the EntityFramework assembly. In .NET 4.5 these annotations were moved to be part of the .NET Framework in the System.ComponentModel.DataAnnotations.Schema namespace of the System.ComponentModel.DataAnnotations.dll assembly. If you are using EF 4.x and targeting .NET 4.5 this results in two data annotations with the same name in different assemblies. Because the annotations in the .NET Framework are in a different namespace we were not able to use type forwarding to avoid this conflict.

It is possible to use EF 4.x on .NET 4.5 but we recommend using the latest pre-release version of EF 5. If you are not using the affected data annotations there is no impact on your code. If you are using the data annotations in a C# project you can use the extern modifier to ensure your code uses the annotations from EntityFramework.dll (http://msdn.microsoft.com/en-us/library/e59b22c5(v=VS.80).aspx). If you use the new annotations from the System.ComponentModel.DataAnnotations.dll assembly in .NET 4.5 they will not be processed by Code First.

The affected annotations are:

  • Column
  • ComplexType
  • DatabaseGenerated
  • DatabaseGeneratedOption
  • ForeignKey
  • InverseProperty
  • MaxLength
  • MinLength
  • NotMapped
  • Table

At that point I realised that my data project was freshly created in VS2012 and was by default targeting .Net 4.5 and the rest of my project in solutions were migrated from VS2010 and targeting .Net 4.0. So I have updated all the projects to target .Net 4.5 and got the pre-release of EntityFramework 5.0.

Make sure you update your projects first to Net4.5, after that do update EF to 5.0, otherwise it will hate you forever and many bunnies will die.

This screencast is a great starter for updating to EF5.0

At that point my error was gone, but I was getting different one. I could not add migration because it could not find Migration Configuration, even though I had configuration set up just seconds before it. That again took a lot of fiddling with NuGet, uninstalling ad re-installing packages. Then I saw in packages.config lines like this:

package id="EntityFramework" version="5.0.0-rc" targetFramework="net40" 

I have changed targetFrameworkto "net45" and now I'm getting the expected behavior from migrations. I guess there would be a better way to get nuget target .Net 4.5 with packages, but that's what worked for me.

I hope this will save somebody banging their head on a wall.