3

I am using C# and Entity Framework. I want to define a key for the SimulationParameter object as a combination of three columns (Name, StudyId, SimulationId). I don't need an ID column, since the combination of those three elements will always be unique.

Simulation Parameter:

public class SimulationParameter : IAggregateRoot
    {
        public SimulationParameter()
        {
        }

        public String SimulationId { get; set; }

        public Guid StudyId { get; set; }

        public Study Study { get; set; }

        public String Name { get; set; }
        public String Value { get; set; }        
    }

Simulation Parameter Mapping:

class SimulationParameterMap : EntityTypeConfiguration<SimulationParameter>
    {
        public SimulationParameterMap()
        {
          HasKey(e => new {SimulationId = e.SimulationId, Name = e.Name, StudyId = e.StudyId});            

        Property(e => e.SimulationId)
            .IsRequired(); 

        Property(e => e.Name)
            .IsRequired(); 

        Property(e => e.Value)
            .IsRequired();

        HasRequired(e => e.Study)
            .WithMany(e => e.SimulationsParameters)
            .HasForeignKey(s => s.StudyId);

        ToTable("SimulationParameters");
        }
    }

Now, when I try to create the model, I have the following error:

    EntityType 'SimulationParameter' has no key defined. Define the key for this EntityType.
SimulationParameters: EntityType: EntitySet 'SimulationParameters' is based on type 'SimulationParameter' that has no keys defined.

I am really clueless on why this is not valid...

Edit 1:

Based on a suggestion, I added the [Key] attribute above the field in the model:

 public class SimulationParameter : IAggregateRoot
    {
        public SimulationParameter()
        {
        }

        [Key]
        public String SimulationId { get; set; }
        [Key]
        public Guid StudyId { get; set; }

        public Study Study { get; set; }
        [Key]
        public String Name { get; set; }
        public String Value { get; set; }

    }

And got a different error:

System.InvalidOperationException: Unable to determine composite primary key ordering for type 'SimulationParameter'. Use the ColumnAttribute (see http://go.microsoft.com/fwlink/?LinkId=386388) or the HasKey method (see http://go.microsoft.com/fwlink/?LinkId=386387) to specify an order for composite primary keys.

Edit2

I was able to make it work doing the following:

  public class SimulationParameter : IAggregateRoot
    {
        public SimulationParameter()
        {
        }

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

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

        public Study Study { get; set; }

        [Key, Column(Order = 3)]
        public String Name { get; set; }

        public String Value { get; set; }



    }

It is still strange though that it isn't working using fluent, I'll keep looking and keep you posted.

Etienne Noël
  • 5,988
  • 6
  • 48
  • 75
  • `SimulationParameter` is an object of what class? Can you post the code for your class – Phani Nov 21 '14 at 19:25
  • I updated the question with the code. – Etienne Noël Nov 21 '14 at 19:27
  • What happens if you add `[Key]` above each of those fields in the model? Are you sure its recognizing your fluent code? That should be working – John Nov 21 '14 at 20:27
  • It is recognizing my fluent code since if I don't put multiple keys, my db gets created. I'll try that. – Etienne Noël Nov 21 '14 at 20:34
  • I got a different error by putting [Key] above SimulationId, StudyId and Name. `System.InvalidOperationException: Unable to determine composite primary key ordering for type 'SimulationParameter'. Use the ColumnAttribute (see http://go.microsoft.com/fwlink/?LinkId=386388) or the HasKey method (see http://go.microsoft.com/fwlink/?LinkId=386387) to specify an order for composite primary keys.` – Etienne Noël Nov 21 '14 at 20:36
  • It should be `[Key, Column(0)]`, `[Key, Column(1)]` etc. – Gert Arnold Nov 21 '14 at 20:49

1 Answers1

1

You can't use a property in another class as primary key: e.Study.Id. SimulationParameter should also have a StudyId (or something like it) in the database. Just take this field into the class and make it part of the key:

public class SimulationParameter : IAggregateRoot
{
    public SimulationParameter()
    {
    }

    public String SimulationId { get; set; }

    [ForeignKey("Study")]
    public int StudyId { get; set; }
    public Study Study { get; set; }

    public String Name { get; set; }
    public String Value { get; set; }            
}

Or, with fluent mapping:

HasRequired(e => e.Study)
.WithMany(e => e.SimulationsParameters)
.HasForeignKey(s => s.StudyId);
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291