web-dev-qa-db-fra.com

Fusionner MyDbContext avec IdentityDbContext

J'ai un MyDbContext dans un projet de bibliothèque de classe Data Accass Layer séparé. Et j'ai un projet ASP.NET MVC 5 avec un IdentityDbContext par défaut. Les deux contextes utilisent la même base de données et je souhaite utiliser la table AspNetUsers en clé étrangère pour certaines de mes tables . Je souhaite donc fusionner les deux contextes et utiliser également l'identité ASP.NET.

Comment puis-je faire ceci?

S'il vous plaît des conseils,

Voici mon contexte après la fusion:

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>();
    }
}

Voici ma classe 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");
             }
         }
     }

Une exception de type 'System.Data.Entity.ModelConfiguration.ModelValidationException' s'est produite dans EntityFramework.dll mais n'a pas été gérée dans le code utilisateur

Informations complémentaires : Une ou plusieurs erreurs de validation ont été détectées lors de la génération du modèle:

Mise à jour: j'ai trouvé la solution.

J'ai dû supprimer cette convention de nommage:

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

Et migrez le modèle ef cf vers db, pour renommer mes tables avec les conventions de nommage de l’identité asp.net . Cela fonctionne maintenant!

48
martonx
  1. Déplacez la définition ApplicationUser dans votre DAL.
  2. Héritez votre MyDbContext de IdentityDbContext<ApplicationUser> ou IdentityDbContext
  3. OnModelCreating - Fournit les informations de clé étrangère.
  4. Passez MyDbContext lors de la création du UserManager<ApplicationUser>
29
jd4u

Vous pouvez obtenir le message suivant si vous suivez les étapes ci-dessus mais ne parvenez pas à déterminer comment fournir les informations clés. L'erreur que vous pouvez recevoir est la suivante:

IdentityUserLogin :: EntityType 'IdentityUserLogin' n'a pas de clé définie. Définissez la clé pour ce type d'entité . Context.IdentityUserRole :: EntityType 'IdentityUserRole' n'a pas de clé définie Définissez la clé pour ce type d'entité.

Créer les deux classes suivantes

public class IdentityUserLoginConfiguration : EntityTypeConfiguration<IdentityUserLogin>
{

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

}

public class IdentityUserRoleConfiguration : EntityTypeConfiguration<IdentityUserRole>
{

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

}

Dans la méthode OnModelCreating de vos applications, DbContext ajoute les deux configurations décrites ci-dessus au modèle:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

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

    }

Cela devrait maintenant vous débarrasser des méthodes d'erreur lors de la création de votre modèle. Ça l'a fait pour moi.

6
dotnethaggis

C'est peut-être un vieux fil, mais cet article a été très utile pour montrer comment obtenir la solution à la question ci-dessus: http://blogs.msdn.com/b/webdev/archive/2014/03 /20/test-announcing-rtm-of-asp-net-identity-2-0-0.aspx

J'ai fini d'avoir à inclure

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

car sans cela, j'obtiendrais l'erreur suivante:

EntityType 'IdentityUserRole' n'a pas de clé définie. Définissez la clé pour ce EntityType . EntityType 'IdentityUserLogin' n'a pas de clé définie. Définissez la clé pour ce EntityType . EntitySet 'IdentityUserRoles' est basé sur le type 'IdentityUserRole' qui n'a pas de clé définie . EntitySet 'IdentityUserLogins' est basé sur le type 'IdentityUserLogin' pour lequel aucune clé n'est définie.

Si j'ajoute ces configurations comme mentionné ci-dessus:

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

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

cela créerait une clé étrangère supplémentaire appelée Application_User.

4
ShadowMinhja

Il est à noter que si vous fusionnez les DBContexts, vous liez une approche d'authentification (l'identité ASP dans ce cas) à l'implémentation d'accès aux données (EF). Du point de vue de la conception du code, cela pourrait être perçu comme un mélange de vos préoccupations et d’une violation du principe de responsabilité unique .

C’est probablement très bien dans la majorité des cas, mais si vous souhaitez réutiliser votre couche de données dans d’autres applications non Web (par exemple, pour une application de bureau ou serveur), cela posera un problème car IdentityDbContext réside dans le Microsoft.AspNet. Identity.EntityFramework namespace et vos applications de bureau ou serveur n'utiliseront probablement pas AspNet Identity comme mécanisme d'authentification.

Nous étions dans cette situation et avons fini par conserver le deuxième contexte de base de données d'ASP, qui est resté dans le projet Web. Nous avons ensuite transféré certaines des données relatives à l'utilisateur (prénom, nom de famille, etc.) dans l'objet de réclamation de l'identité lors de la connexion de l'utilisateur. 

1
tomRedox

1) Une fois que vous avez hérité du contexte d'IdentityDbContext, les erreurs liées aux clés primaires des tables d'identité (AspNetUsers, etc.) doivent disparaître. 

2) Il manque des propriétés de navigation à votre extension ApplicationUser d'IdentityUser interprétées comme des clés étrangères par Entity Framework (elles sont également très utiles pour la navigation à partir de votre code).

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) J'ai lu dans de nombreux endroits que, lorsque vous surmontez OnModelCreating, vous devez appeler la méthode de base. Il semble que parfois vous pouvez vous en passer. 

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

Le problème est dû au fait que vous avez remplacé le contenu de la méthode "OnModelCreating" implémentée dans la classe IdentityUser.

Vous devez d'abord appeler la méthode OnModelCreating à partir de la classe de base, puis ajouter votre code. Donc, votre méthode OnModelCreating devrait ressembler à ceci:

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

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

J'ai donné une réponse complète à cette question ici . Voici la réponse courte:

Basé sur le code source d'IdentityDbContext, si nous voulons fusionner IdentityDbContext avec notre DbContext, nous avons deux options:

Première option:
Créez un DbContext qui hérite d'IdentityDbContext et ayez accès aux classes.

   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
}

Deuxième option: (non recommandé) 
En réalité, nous n'avons pas à hériter d'IdentityDbContext si nous écrivons tout le code nous-mêmes. 
Donc, nous pouvons simplement hériter de DbContext et implémenter notre version personnalisée de "OnModelCreating (constructeur ModelBuilder)" à partir du code source IdentityDbContext

0
Arvand