Integrating SimpleMembership with Entity Framework

asp.net-mvc-4 entity-framework simplemembership

Question

I'm trying to integrate the SimpleMembership tables with the rest of my Object Model - to manage all the entities from a single database and context.

Up to now the best recipe I've found for manually spinning up the SM tables (the entry point to combine SimpleMember with the rest of my Object Model) is found here. But, as cited in the comments section there are a couple mistakes in the code sample provided. The comments attempt to provide corrections but, due to formatted, really hard to follow.

I'm 80% the way there but getting stuck with the Foreign Key generation for the Membership table. Does the code within OnModelCreating block belong in the MyDbContext class? I'm getting a compile error on the .WithMany(u => u.Members) line.

Membership.cs

[Table("webpages_Membership")]
public class Membership
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int UserId { get; set; }
    public DateTime? CreateDate { get; set; }

    [StringLength(128)]
    public string ConfirmationToken { get; set; }
    public bool? IsConfirmed { get; set; }
    public DateTime? LastPasswordFailureDate { get; set; }
    public int PasswordFailuresSinceLastSuccess { get; set; }

    [Required, StringLength(128)]
    public string Password { get; set; }
    public DateTime? PasswordChangedDate { get; set; }

    [Required, StringLength(128)]
    public string PasswordSalt { get; set; }

    [StringLength(128)]
    public string PasswordVerificationToken { get; set; }
    public DateTime? PasswordVerificationTokenExpirationDate { get; set; }

    <strike>public virtual ICollection<Role> Roles { get; set; }</strike>

EDIT: Originally I added the line above to remove a compiler complaint in the extraneous code block below. Removing this attempt to create a FK to Roles will align the rest of this code so that these model classes create a Migration that generates tables for SM.

OAuthMembership.cs

[Table("webpages_OAuthMembership")]
public class OAuthMembership
{
    [Key, Column(Order = 0), StringLength(30)]
    public string Provider { get; set; }
    [Key, Column(Order = 1), StringLength(100)]
    public string ProviderUserId { get; set; }
    public int UserId { get; set; }
}

Role.cs

[Table("webpages_Roles")]
public class Role
{
    [Key]
    public int RoleId { get; set; }
    [StringLength(256)]
    public string RoleName { get; set; }

    public virtual ICollection<UserProfile> UserProfiles { get; set; }
}

UserProfile.cs

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<Role> Roles { get; set; }
}

MyDbContext.cs

public MyDbContext() : base("DefaultConnection") { }

public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Membership> Membership { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<OAuthMembership> OAuthMembership { get; set; }


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<UserProfile>()
                .HasMany<Role>(r => r.Roles)
                .WithMany(u => u.UserProfiles)
                .Map(m =>
                         {
                             m.ToTable("webpages_UsersInRoles");
                             m.MapLeftKey("UserId");
                             m.MapRightKey("RoleId");
                         });

EDIT: The block below was included in one of the article's comments but seems not to be needed.

    //modelBuilder.Entity<Membership>()
    //    .HasMany<Role>(r => r.Roles)
    //    .WithMany(u => u.Members)
    //    .Map(m =>
    //    {
    //        m.ToTable("webpages_UsersInRoles");
    //        m.MapLeftKey("UserId");
    //        m.MapRightKey("RoleId");
    //    });

}

}

1
3
3/20/2013 7:40:08 PM

Popular Answer

I followed the instructions in the article, and I also took into account the the comments that suggested the article was wrong in a few ways.

I ended up with the following classes:

UserProfile.cs

[Table("UserProfile")]
public class UserProfile
{
    [Key, ForeignKey("Membership")]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public ICollection<WebSecurity.Role> Roles { get; set; }
    public WebSecurity.Membership Membership { get; set; }
}

You should notice right away the "ForeignKey" attribute I use on the UserId column. Since the user is first created in the Membership table, my UserProfile table is the dependent table.

Membership.cs

[Table("webpages_Membership")]
public class Membership
{
    //public Membership()
    //{
    //  Roles = new List<Role>();
    //  OAuthMemberships = new List<OAuthMembership>();
    //}

    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int UserId { get; set; }
    public DateTime? CreateDate { get; set; }
    [StringLength(128)]
    public string ConfirmationToken { get; set; }
    public bool? IsConfirmed { get; set; }
    public DateTime? LastPasswordFailureDate { get; set; }
    public int PasswordFailuresSinceLastSuccess { get; set; }
    [Required, StringLength(128)]
    public string Password { get; set; }
    public DateTime? PasswordChangedDate { get; set; }
    [Required, StringLength(128)]
    public string PasswordSalt { get; set; }
    [StringLength(128)]
    public string PasswordVerificationToken { get; set; }
    public DateTime? PasswordVerificationTokenExpirationDate { get; set; }


    public UserProfile UserProfile { get; set; }
}

Per Richard's comments in the article, I commented out the constructor. I also created a reference back to the UserProfile, but not to roles.

OAuthMembership.cs

[Table("webpages_OAuthMembership")]
public class OAuthMembership
{
    [Key, Column(Order = 0), StringLength(30)]
    public string Provider { get; set; }

    [Key, Column(Order = 1), StringLength(100)]
    public string ProviderUserId { get; set; }

    public int UserId { get; set; }

    //[Column("UserId"), InverseProperty("OAuthMemberships")]
    //public Membership User { get; set; }
}

My OAuthMembership class remained basically the same; I commented out only the User attribute, per Richard's comment in the article.

AccountModel.cs+UsersContext

Finally, the UserContext class, where I create the association for the UsersInRoles table.

public class UsersContext : DbContext

{

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

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<InternetApplication.Models.WebSecurity.Role>()
            .HasMany<InternetApplication.Models.UserProfile>(r => r.UserProfiles)
            .WithMany(u => u.Roles)
            .Map(m =>
            {
                m.ToTable("webpages_UsersInRoles");
                m.MapLeftKey("UserId");
                m.MapRightKey("RoleId");
            });
    }

    public DbSet<WebSecurity.Membership> Membership { get; set; }
    public DbSet<WebSecurity.OAuthMembership> OAuthMembership { get; set; }
    public DbSet<WebSecurity.Role> Roles { get; set; }
    public DbSet<UserProfile> UserProfiles { get; set; }
}

In addition to adding the UsersInRoles mapping, I added DbSet entries for each table.

Now that everything has been created, I can use my Add-Migration and Update-Database commands and use the following code snippet that combines the Membership, UserProfile, and Roles tables:

using (var db = new UsersContext())
{
    var memberships = db.Membership
        .Include("UserProfile")
        .Include("UserProfile.Roles")
        .ToList();
    foreach (var member in memberships)
    {
        member.IsConfirmed = true;
    }

    db.SaveChanges();
}

This was a long post, but I hope that helps.

3
4/5/2013 2:46:05 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow