6

Я нахожусь в VS 2013 и только что создал приложение MVC.Внешний ключ к Microsoft.AspNet.Identity.EntityFramework.IdentityUser?

Я создаю объект, в котором я намерен иметь внешний ключ в таблице AspNetUsers в полученной базе данных. В проекте есть ApplicationUser (полученный от IdentityUser), который выглядит как сопоставление свойств-столбцов с таблицей AspNetUsers.

Как мы правильно объявляем внешний ключ?

public MyObject 
{ 
    public string UserId { get; set; } 

    [ForeignKey("UserId")] 
    public ApplicationUser User { get; set;} 

    // other properties 
} 

Теперь я могу изменить ApplicationUser иметь коллекцию MyObjects:

public ApplicationUser : IdentityUser 
{ 
    public virtual ICollection<MyObject> MyObjects { get; set; }  
} 

Это, кажется, как сделать один-ко-многим в EF Code First. Однако, когда я обновляю-базу данных, я получаю ошибки, которые говорят, что члены Identity (IdentityUserLogin, IdentityUserRole и т. Д.) Не имеют определенных ключей. Возможно, эти классы не были предназначены для участия в EF Code First Migrations?

Я мог бы пойти «на спину» и добавить внешний ключ с помощью операторов SQL, но если бы я хотел снова обновить его из Code First, я мог бы получить ошибки (что база данных в настоящее время не соответствует более старой миграции или чем-то как это).

Каким образом мы должным образом ссылаемся на эти таблицы членства?

Я также попытался создать класс AspNetUser с соответствующими свойствами таблицы AspNetUsers. Вместо «public ApplicationUser» в классе Client я объявлял «public AspNetUser». В результате этого произошел сбой миграции - «Автоматическая миграция не была применена, поскольку это приведет к потере данных».

Итак, что делать?

+1

Я бы сделал предложение, избегая использования атрибутов для определения ваших отношений Entityframework. Если вы планируете использовать этот объект за пределами приложения базы данных, это затрудняет выполнение атрибутов. – BlackICE

+0

У меня такая же проблема, вы ее решили? – Luther

ответ

0

В классах идентификации ASP.NET не используются атрибуты для определения отношений, они ожидают, что отношения будут настроены DbContext.

По умолчанию DbContext, используемый с идентификатором ASP.NET, IdentityDbContext<TUser> включает в себя конфигурацию. Поэтому, если вы наследуете класс DbContext наследуемым от IdentityDbContext<ApplicationUser>, вы должны быть установлены.

Update

Если вы все еще получаете сообщение об ошибке: «Автоматическая миграция не была применена, так как это приведет к потере данных.» затем сделать:

get Update-Database -Force 

Если вы все еще получаете сообщения об ошибках IdentityUserLogin, IdentityUserRole и т.д. не имеет ключей не определен , то вы, скорее всего, переопределяетесь методом OnModelCreating в вашем DbContext без вызова метода базового первым. Добавьте вызов к основанию, как это:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    base.OnModelCreating(modelbuilder); 
    // your code here 
} 

Конец обновления

Если вы не хотите, чтобы наследовать от IdentityDbContext вам необходимо добавить конфигурацию для классов идентичности. Один из способов сделать это - переопределить OnModelCreating. Здесь IdentityDbContext<ApplicationUser> сконфигурируйте сопоставления структур сущности. Если вы добавите это в свой класс DbContext, он должен настроить необходимые вам сопоставления.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId); 
    modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id); 
    modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId }); 
} 
+1

Я попытался наследовать IdentityDbContext - не работает. Я все равно получаю ту же ошибку, когда пытаюсь выполнить миграцию. –

+0

Обновлен мой ответ с некоторой информацией о том, что делать в зависимости от того, какую ошибку вы получите после того, как вы наследуете DbContext из класса IdentityDbContext

+0

У меня возникла ошибка «.. привести к потере данных», когда я создал класс AspNetUser вручную и включил его в миграцию. Я также получил эту ошибку, когда я переопределил OnModelCreating с 3 операторами FK без наследования IdentityDbContext . Когда я унаследовал IdentityDbContext , как указано в документации, я все равно получаю ошибки «без ключей» - я думал, что IdentityDbContext объявил эти ключи, которые позаботятся обо всем. –

0

Я думаю, что у вас есть это в обратном направлении. Может быть, попробуйте что-нибудь вроде:

public MyCustomUser : IUser 
{ 
    public string Id { get; set; } 

    public string FavoriteHairColor { get; set;} 
} 

public ApplicationUser : IdentityUser 
{ 
    public virtual ICollection<MyCustomUser> MyCustomUsers{ get; set; }  
} 

Я собираюсь из памяти здесь, чтобы быть немного. В любом случае, важно, чтобы ваш пользовательский класс EF наследовал от IUser.

+1

Я не пытаюсь наследовать MyCustomUser. Я пытаюсь, чтобы MyObject имел внешний ключ для ApplicationUser. –

+0

Как достичь этого с помощью Fluent API? – MichaelMao

+0

@MichaelMao - Пожалуйста, взгляните на мое решение о том, как достичь этого, используя Fluent API. На самом деле, вам не нужен Fluent API, если вы довольны именем внешнего ключа, по умолчанию «ApplicationUser_Id» по соглашению EF. Однако, если вы хотите настроить имя внешнего ключа, тогда это необходимо. – kimbaudi

0
public MyObject 
{ 
    .. other properties 

    [MaxLength(128), ForeignKey("ApplicationUser")] 
    public virtual string UserId { get; set; } 

    public virtual ApplicationUser ApplicationUser { get; set;} 
} 
+0

В чем причина последней строки: 'public virtual ApplicationUser ApplicationUser {get; задавать; } '? Должно ли быть недостаточно, чтобы ForeignKey для ApplicationUser в строке выше? – ToastyMallows

1

Я хотел бы сделать следующее: В ApplicationUser классе, добавить атрибут ForeignKey,

public ApplicationUser : IdentityUser { 
    [ForeignKey("UserID")] 
    public virtual ICollection<MyCustomUser> MyCustomUsers{ get; set; }  
} 

и в модели, где вы хотите, чтобы отслеживать, к которой пользователь принадлежит,

public MyObject { 
    public string UserId { get; set; } 

    // other properties 
} 

Вам не нужно хранить весь экземпляр ApplicationUser в классе MyObject, а UserID будет сгенерирован автоматически. Важно, чтобы он имел тип string, равно как IDApplicationUser!

+0

Я предпочитаю избегать использования атрибутов для определения отношений EF, поскольку @BlackICE предлагает и избегал использования '[ForeignKey]'. Мое решение использует Fluent API для определения отношения, которое, как я считаю, намного чище. Конечно, API Fluent не нужен, если вы хотите, чтобы внешний ключ назывался «ApplicationUser_Id» по соглашению. – kimbaudi

3

Легко создать отношения «один ко многим» между ApplicationUser и MyObject и добавить внешний ключ «UserId» в таблицу MyObjects. Что мне нравится в этом решении является то, что следует конвенции EF и нет необходимости [ForeignKey] атрибут в модели:

public class ApplicationUser : IdentityUser 
{ 
    public virtual ICollection<MyObject> MyObjects { get; set; } 
} 

public class MyObject 
{ 
    public int MyObjectId { get; set; } 

    public string MyObjectName { get; set; } 

    // other properties 

    public virtual ApplicationUser ApplicationUser { get; set; } 
} 

public class ApplicationDbContext : IdentityDbContext<ApplicationUser> 
{ 
    public ApplicationDbContext() 
     : base("DefaultConnection", throwIfV1Schema: false) 
    { 
    } 

    public DbSet<MyObject> MyObjects { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Entity<MyObject>() 
      .HasRequired(c => c.ApplicationUser) 
      .WithMany(t => t.MyObjects) 
      .Map(m => m.MapKey("UserId")); 
    } 
} 

Обратите внимание на использование Fluent API для создания «USERID» внешний ключ в вашем MyObjects таблице. Это решение по-прежнему будет работать без добавления Fluent API, но тогда ваш столбец внешнего ключа будет иметь имя «ApplicationUser_Id» в вашей таблице MyObjects.

Смежные вопросы