简体   繁体   中英

EF6 Code first model ForeignKey

i got the an exception when i am trying to generate the database out of the followed model.

The ForeignKeyAttribute on property 'DataCenterBenchmark' on type 'Benchmark.Data.Context' is not valid. The foreign key name 'BenchmarkId' was not found on the dependent type 'Benchmark.Data.Context'. The Name value should be a comma separated list of foreign key property names.

[Table("Contexts")]
public class Context
{
    [Key]
    public Guid InternalId { get; set; }

    [Required] public string Name { get; set; }
    [Required] public string Cluster { get; set; }
    [Required] public string Token { get; set; }
    [Required] public string IP { get; set; }
    [Required] public string Memo { get; set; }
    [Required] public string BenchType { get; set; }

    [Required] public int InstanceCount { get; set; }
    [Required] public int ThreadCount { get; set; }
    [Required] public int RequestCount { get; set; }

    [Required] public DateTime CreationDate { get; set; }
    [Required] public DateTime EditDate { get; set; }

    [ForeignKey("BenchmarkId")]
    public Benchmark RemoteBenchmark { get; set; }
    [ForeignKey("BenchmarkId")]
    public Benchmark DataCenterBenchmark { get; set; }
    [ForeignKey("BenchmarkId")]
    public Benchmark IISBenchmark { get; set; }
    [ForeignKey("BenchmarkId")]
    public Benchmark LocalBenchmark { get; set; }

    [ForeignKey("MachineTypeId")]
    [Required] public MachineType MachineType { get; set; }
}

[Table("Benchmarks")]
public class Benchmark
{
    [Key]
    public int BenchmarkId { get; set; }
    [Required] public string Result { get; set; }
    [Required] public DateTime Duration { get; set; }
}

[Table("MachineTypes")]
public class MachineType
{
    [Key]
    public int MachineTypeId { get; set; }
    [Required] public string Name { get; set; }
}

public class BenchmarkContext : DbContext
{
    public DbSet<Context> Contexts { get; set; }
    public DbSet<Benchmark> Benchmarks { get; set; }
    public DbSet<MachineType> MachineTypes { get; set; }
}

Tried to fix it with some tutorials - no victory..

Regards, Marc

===== EDIT =====

After removing the [ForeignKey] flags i can't connect to my SQL Server (Error 26). I set no database as connection string so EF6 needs to create a localdb..?

A quick guide through ForeignKey property.

When used on a key property (such as int RemoteBenchmarkId ), its name should point to the navigation property (eg Benchmark RemoteBenchmark ). When used on a navigation property (this time Benchmark RemoteBenchmark ) its name should point to the key property (such as int RemoteBenchmarkId ).

The following code fragments are equivalent:

public class Context {
    //...other properties

    [ForeignKey("RemoteBenchmark")]
    public int RemoteBenchmarkId { get; set; }
    public Benchmark RemoteBenchmark { get; set; }
    }
public class Context {
    //...other properties

    public int RemoteBenchmarkId { get; set; }

    [ForeignKey("RemoteBenchmarkId")]
    public Benchmark RemoteBenchmark { get; set; }
    }

With that in mind, what you probably want is 4 benchmarks, each having their own foreign key column (two benchmark properties using same key would point to the same instance, which is probably not what you want), like here:

public class Context {
    //...other properties

    [ForeignKey("RemoteBenchmark")]
    public int RemoteBenchmarkId { get; set; }
    public Benchmark RemoteBenchmark { get; set; }

    [ForeignKey("DataCenterBenchmark")]
    public int DataCenterBenchmarkId { get; set; }
    public Benchmark DataCenterBenchmark { get; set; }

    [ForeignKey("IISBenchmark")]
    public int IISBenchmarkId { get; set; }
    public Benchmark IISBenchmark { get; set; }

    [ForeignKey("LocalBenchmark")]
    public int LocalBenchmarkId { get; set; }
    public Benchmark LocalBenchmark { get; set; }
    }

Don't forget to use [Required] annotation if context requires specific benchmarks!

Also, you might skip the [ForeignKey] annotations entirely allowing EF to infer columns itself (named <navigation property name>_Id by default, such as RemoteBenchmark_Id ), but then you can't retrieve ids themselves without retrieving entire benchmark. Guess it all depends on specific cases; personally, I don't mind cluttering model with foreign key properties, since sometimes the keys themselves are enough.

(at least [ForeignKey] annotations shouldn't be necessary; if their lack causes errors, it might be another problem entirely...?)

Cheers~!

You can override OnModelCreating method inside BenchmarkContext and to write the relation between tables like below.

Notes: You need to remove attributes [ForeignKey("BenchmarkId")] .

public class BenchmarkContext : DbContext
{
    public DbSet<Context> Contexts { get; set; }
    public DbSet<Benchmark> Benchmarks { get; set; }
    public DbSet<MachineType> MachineTypes { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Context>()
            .HasRequired(m => m.RemoteBenchmark)
            .WithOptional()
            .Map(m => { m.MapKey("RemoteBenchmarkId"); });

        modelBuilder.Entity<Context>()
            .HasRequired(m => m.DataCenterBenchmark)
            .WithOptional()
            .Map(m => { m.MapKey("DataCenterBenchmarkId"); });

        modelBuilder.Entity<Context>()
            .HasRequired(m => m.IISBenchmark)
            .WithOptional()
            .Map(m => { m.MapKey("IISBenchmarkId"); });

        modelBuilder.Entity<Context>()
            .HasRequired(m => m.LocalBenchmark)
            .WithOptional()
            .Map(m => { m.MapKey("LocalBenchmarkId"); });
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM