Объединить MyDbContext с IdentityDbContext

У меня есть MyDbContext в отдельном проекте библиотеки классов Data Accass Layer. И у меня есть проект ASP.NET MVC 5 со стандартным IdentityDbContext. Два контекста используют одну и ту же базу данных, и я хочу использовать таблицу AspNetUsers для внешнего ключа для некоторых моих таблиц. Поэтому я хотел бы объединить два контекста, и я тоже хочу использовать идентификатор ASP.NET.

Как я могу это сделать?

Пожалуйста, совет,

Это мой контекст после слияния:

public class CrmContext : IdentityDbContext<CrmContext.ApplicationUser> //DbContext
{
    public class ApplicationUser : IdentityUser
    {
        public Int16 Area { get; set; }
        public bool Holiday { get; set; }
        public bool CanBePublic { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public CrmContext()
        : base("DefaultConnection")
    {

    }

    public DbSet<Case> Case { get; set; }
    public DbSet<CaseLog> CaseLog { get; set; }
    public DbSet<Comment> Comment { get; set; }
    public DbSet<Parameter> Parameter { get; set; }
    public DbSet<Sign> Sign { get; set; }
    public DbSet<Template> Template { get; set; }
    public DbSet<Read> Read { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

Вот мой класс RepositoryBase:

    public class RepositoryBase<TContext, TEntity> : IRepositoryBaseAsync<TEntity>, IDisposable
        where TContext : IdentityDbContext<CrmContext.ApplicationUser> //DbContext
        where TEntity : class
    {
        private readonly TContext _context;
        private readonly IObjectSet<TEntity> _objectSet;

        protected TContext Context
        {
            get { return _context; }
        }

        public RepositoryBase(TContext context)
        {
            if (context != null)
            {
                _context = context;
                //Here it is the error:
                _objectSet = (_context as IObjectContextAdapter).ObjectContext.CreateObjectSet<TEntity>();
             }
             else
             {
                 throw new NullReferenceException("Context cannot be null");
             }
         }
     }

Исключение типа 'System.Data.Entity.ModelConfiguration.ModelValidationException' произошло в EntityFramework.dll, но не было обработано в коде пользователя

Дополнительная информация. Во время генерации модели были обнаружены одна или несколько ошибок проверки:

Обновление: я нашел решение.

Мне пришлось удалить это соглашение об именах:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}

И перенесите модель ef cf в db, чтобы переименовать мои таблицы с условными обозначениями имени asp.net. Он работает сейчас!

Ответ 1

  • Переместите определение ApplicationUser в DAL.
  • Наследуйте MyDbContext от IdentityDbContext<ApplicationUser> или IdentityDbContext
  • OnModelCreating - информация о внешнем ключе.
  • Pass MyDbContext при создании UserManager<ApplicationUser>

Ответ 2

Вы можете получить следующее сообщение, если выполните указанные выше шаги, но не можете определить, как предоставить ключевую информацию. Ошибка, которую вы можете получить:

IdentityUserLogin:: EntityType 'IdentityUserLogin' не имеет ключа. Определите ключ для этого EntityType. Context.IdentityUserRole:: EntityType 'IdentityUserRole' не имеет ключа. Определите ключ для этого EntityType.

Создайте два следующих класса

public class IdentityUserLoginConfiguration : EntityTypeConfiguration<IdentityUserLogin>
{

    public IdentityUserLoginConfiguration()
    {
        HasKey(iul => iul.UserId);
    }

}

public class IdentityUserRoleConfiguration : EntityTypeConfiguration<IdentityUserRole>
{

    public IdentityUserRoleConfiguration()
    {
        HasKey(iur => iur.RoleId);
    }

}

В методе OnModelCreating в ваших приложениях DbContext добавьте две модели, описанные выше, в модель:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Configurations.Add(new IdentityUserLoginConfiguration());
        modelBuilder.Configurations.Add(new IdentityUserRoleConfiguration());

    }

Теперь это должно избавиться от методов ошибок при создании вашей модели. Это было для меня.

Ответ 3

Это может быть старый поток, но эта статья очень помогла в демонстрации того, как получить решение вышеуказанного вопроса: http://blogs.msdn.com/b/webdev/archive/2014/03/20/test-announcing-rtm-of-asp-net-identity-2-0-0.aspx

Мне пришлось включить

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

потому что без него я получаю следующую ошибку:

EntityType 'IdentityUserRole' не имеет ключа. Определите ключ для этого EntityType. EntityType 'IdentityUserLogin' не имеет ключа. Определите ключ для этого EntityType. EntitySet "IdentityUserRoles" основан на типе "IdentityUserRole", который не имеет определенных ключей. EntitySet "IdentityUserLogins" основан на типе "IdentityUserLogin", который не имеет определенных ключей.

Если я добавлю эти конфигурации, как указано выше:

public class IdentityUserLoginConfiguration : EntityTypeConfiguration<IdentityUserLogin>
{
    public IdentityUserLoginConfiguration()
    {
        HasKey(iul => iul.UserId);
    }
}

public class IdentityUserRoleConfiguration : EntityTypeConfiguration<IdentityUserRole>
{
    public IdentityUserRoleConfiguration()
    {
        HasKey(iur => iur.RoleId);
    }
}

он создаст дополнительный внешний ключ, называемый Application_User.

Ответ 4

1) После того, как вы наследуете контекст из IdentityDbContext, ошибки, связанные с первичными ключами в таблицах Identity (AspNetUsers и т.д.), должны исчезнуть.

2) В расширении ApplicationUser для IdentityUser отсутствуют свойства навигации, которые интерпретируются как внешние ключи с помощью Entity Framework (они также очень полезны для навигации по вашему коду).

public class ApplicationUser : IdentityUser
{
    public Int16 Area { get; set; }
    public bool Holiday { get; set; }
    public bool CanBePublic { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    //*** Add the following for each table that relates to ApplicationUser (here 1-to-many)
    public virtual IList<Case> Cases { get; set; } //Navigation property
    //*** and inside the case class you should have 
    //*** both a public ApplicationUser ApplicationUser {get;set;}
    //*** and a public string ApplicationUserId {get;set;} (string because they use GUID not int)
}

3) Во многих местах я читал, что, преодолевая OnModelCreating, вы должны вызвать базовый метод. Кажется, что иногда вы можете обойтись без него.

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

Ответ 5

Стоит отметить, что при объединении DBContexts вы связываете подход аутентификации (в данном случае ASP Identity) с реализацией доступа к данным (EF). С точки зрения разработки кода это можно рассматривать как смешение ваших опасений и нарушение принципа единой ответственности.

Это, вероятно, хорошо в большинстве случаев, но если вы хотите повторно использовать слой данных в других не-веб-приложениях (например, для настольных или серверных приложений), это создаст проблему, поскольку IdentityDbContext находится в Microsoft.AspNet.Identity.EntityFramework. пространство имен и ваши приложения для настольных компьютеров или серверов вряд ли будут использовать AspNet Identity в качестве механизма аутентификации.

Мы оказались в такой ситуации и в итоге сохранили второй контекст БД ASP, который остался в веб-проекте. Затем мы перекрестно загрузили некоторые данные о пользователе (имя, фамилия и т.д.) В объект утверждений Identity при входе пользователя.

Ответ 6

Я дал полный ответ на этот вопрос здесь. Вот короткий ответ:

На основе исходного кода IdentityDbContext, если мы хотим объединить IdentityDbContext с нашим DbContext, у нас есть два варианта:

Первый вариант:
Создайте DbContext, который наследует от IdentityDbContext и имеет доступ к классам.

   public class ApplicationDbContext 
    : IdentityDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    // Add additional items here as needed
}

Второй вариант: (не рекомендуется)
На самом деле нам не нужно наследовать от IdentityDbContext, если мы сами напишем весь код.
Таким образом, в основном мы можем просто наследовать от DbContext и реализовать нашу настраиваемую версию "OnModelCreating (ModelBuilder builder)" из исходный код IdentityDbContext

Ответ 7

Проблема была вызвана тем, что вы перезаписали содержимое метода "OnModelCreating", который реализован в классе IdentityUser.

Сначала необходимо вызвать метод OnModelCreating из базового класса, а затем добавить свой код. Итак, ваш метод OnModelCreating должен выглядеть так:

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

     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}

Ответ 8

Я попробовал простой способ. Скопируйте строку подключения из своего db и замените строку соединения DefaultConnection. Идем дальше и создаем пользователя, все необходимые таблицы автоматически создаются в вашей базе данных.

Надеюсь, что поможет