Сопоставление составных ключей с использованием сначала кода EF

115

Таблица сервера sql:

SomeId PK varchar(50) not null 
OtherId PK int not null

Как мне сначала отобразить это в коде EF 6?

public class MyTable
{
    [Key]
    public string SomeId { get; set; }

    [Key]
    public int OtherId { get; set; }
}

Я видел несколько примеров, когда вам нужно установить порядок для каждого столбца, это требуется?

Есть ли где-нибудь официальная документация по этому поводу?

loyalflow
источник
Является ли или ? SomeIdstringint
Кори Адлер
@ IronMan84 Это строка, я это исправлю.
loyalflow 05

Ответы:

187

Вам обязательно нужно указать порядок столбцов, иначе как SQL Server должен знать, какой из них идет первым? Вот что вам нужно сделать в своем коде:

public class MyTable
{
  [Key, Column(Order = 0)]
  public string SomeId { get; set; }

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

Вы также можете посмотреть на этот вопрос SO . Если вам нужна официальная документация, я бы порекомендовал заглянуть на официальный сайт EF . Надеюсь это поможет.

РЕДАКТИРОВАТЬ: Я только что нашел сообщение в блоге Джули Лерман со ссылками на все виды добра EF 6. Вы можете найти все , что вам нужно здесь .

Кори Адлер
источник
Как это сделать с помощью EntityConfiguration? На самом деле у меня нет сущности для объединенной таблицы ... У меня есть только две сущности и EntityConfiguration на одном из них с .Map () для настройки сопоставления.
Мир
31
otherwise how is SQL Server supposed to know which one goes first?- почему бы не таким же образом узнать порядок для всех остальных столбцов?
Давор
1
EF не знает порядок других столбцов, вы можете вставлять столбцы в любом порядке, если указаны имена. Если EF требует порядок составного PK, он должен быть связан с индексацией.
Sylvain Gantois
@Davor Я полагаю, что создатели EF могли бы использовать отражение, чтобы вывести порядок ключей / столбцов, но, возможно, есть соображения производительности, чтобы этого не делать. В любой день я предпочитаю специфику времени разработки более низкой производительности, особенно в моем DAL.
Джейкоб Штамм
47

Для сопоставления составного первичного ключа с использованием Entity framework мы можем использовать два подхода.

1) Путем переопределения метода OnModelCreating ()

Например: у меня есть класс модели с именем VehicleFeature, как показано ниже.

public class VehicleFeature
{
    public int VehicleId { get; set; }
    public int FeatureId{get;set;}
    public Vehicle Vehicle{get;set;}
    public Feature Feature{get;set;}
}

Код в моем DBContext будет выглядеть так:

public class VegaDbContext : DbContext
{
    public DbSet<Make> Makes{get;set;}

    public DbSet<Feature> Features{get;set;}
    public VegaDbContext(DbContextOptions<VegaDbContext> options):base(options)        
    {           

    }
    // we override the OnModelCreating method here.
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<VehicleFeature>().HasKey(vf=> new {vf.VehicleId, vf.FeatureId});
    }
}

2) По аннотациям данных.

public class VehicleFeature
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  
    [Key]
    public int VehicleId { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]   
    [Key]
    public int FeatureId{get;set;}
    public Vehicle Vehicle{get;set;}
    public Feature Feature{get;set;}
}

Пожалуйста, перейдите по ссылкам ниже для получения дополнительной информации.

1) https://msdn.microsoft.com/en-us/library/jj591617(v=vs.113).aspx

2) Как добавить составной уникальный ключ с помощью EF 6 Fluent Api?

Кришна
источник
5
FYI для EF Core, вариант № 2 невозможен : «Составные ключи можно настроить только с помощью Fluent API - соглашения никогда не устанавливают составной ключ, и вы не можете использовать аннотации к данным для его настройки».
Tobias J
7

Через конфигурацию вы можете сделать это:

Model1
{
    int fk_one,
    int fk_two
}

Model2
{
    int pk_one,
    int pk_two,
}

затем в контексте config

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Model1>()
            .HasRequired(e => e.Model2)
            .WithMany(e => e.Model1s)
            .HasForeignKey(e => new { e.fk_one, e.fk_two })
            .WillCascadeOnDelete(false);
    }
}
philn5d
источник
Где в конфиге контекста?
Чарли
Если вы настраиваете контекст через код с помощью Fluent API ... раздел 7 . открытый класс MyContext: DbContext {защищенное переопределение void OnModelCreating (DbModelBuilder modelBuilder) {modelBuilder.Entity <Model1> () .HasRequired (e => e.Model2) .WithMany (e => e.Model1s) .HasForeign (e => e.Model1s). {e.fk_one, e.fk_two}) .WillCascadeOnDelete (ложь); }}
philn5d 07
Я обнаружил, что мне пришлось использовать ModelBuilder вместо DbModelBuilder в ядре dotnet.
kiml42
6

Я подумал, что добавлю к этому вопросу, так как это лучший результат поиска Google.

Как было отмечено в комментариях, в EF Core нет поддержки использования аннотаций (ключевой атрибут), и это должно выполняться свободно.

Поскольку я работал над большой миграцией с EF6 на EF Core, это было неприятно, поэтому я попытался взломать его, используя Reflection, чтобы найти атрибут Key, а затем применить его во время OnModelCreating

// get all composite keys (entity decorated by more than 1 [Key] attribute
foreach (var entity in modelBuilder.Model.GetEntityTypes()
    .Where(t => 
        t.ClrType.GetProperties()
            .Count(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(KeyAttribute))) > 1))
{
    // get the keys in the appropriate order
    var orderedKeys = entity.ClrType
        .GetProperties()
        .Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(KeyAttribute)))
        .OrderBy(p => 
            p.CustomAttributes.Single(x => x.AttributeType == typeof(ColumnAttribute))?
                .NamedArguments?.Single(y => y.MemberName == nameof(ColumnAttribute.Order))
                .TypedValue.Value ?? 0)
        .Select(x => x.Name)
        .ToArray();

    // apply the keys to the model builder
    modelBuilder.Entity(entity.ClrType).HasKey(orderedKeys);
}

Я не тестировал это полностью во всех ситуациях, но в моих основных тестах он работает. Надеюсь, это кому-то поможет

cmorgan091
источник