Creating 2 sides relationship between a model to the default ApplicationUser of a basic MVC 5 project. Working with 2 dbContext classes

asp.net-identity asp.net-mvc-5 data-annotations ef-code-first entity-framework-6

Question

I believe it's suppose to be a trivial issue, but I didn't find any relevant answer.

I am working on a MVC 5 project (created by the default VS template with Identity).

I have a Post model. Only an Authorized "user" ("user" is the default ApplicationUser class provided by the EF template when creating the project) can create a post.

I need to Extend the post and the user models in that way:

-Every Post will have the user (who created it)

-Every user will have all the Posts were created by him.

In other words, I need a one to many relationship between Post and users. (my goal is that only post's owner will be able to edit it. Moreover, every "user" can get a list of his posts )

I use EntityFramework 6.1.2 with Identity 2.0 (or 1.0.. not sure how to check?).

The problem:

I have 2 dbContext classes pointing to two different db tables:

1) ApplicationDbContext - The default DbContext provided by the EF when the project was created and points to the AspNetUsers table.

2) MrSaleDB - The DbContext which points to the Posts db-table (and other tables in my model like Galleries and etc. )

So how should I extend the Post and user classes? How can I compare the current user identity to the user who was saved in the extended Post class (in the PostController while user edit a post) ?

Everything I tried didn't work )-;

Here are some code from my project, thanks:

Models:

namespace MrSaleBeta01.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
**public class ApplicationUser : IdentityUser**
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }


//ADDED:

    public ApplicationUser ()
    {
        Posts = new List<Post>();
    }

    public ICollection Posts { get; set; }
}


**public class Post**
{
    [Key]
    public int Id { get; set; }        

    [Required]
    public string Title { get; set; }

    public virtual Gallery Gallery { get; set; }

    [ForeignKey("Category")]
    public int CategoryId { get; set; }
    // Navigation property:
    public virtual Category Category { get; set; }


//ADDED:
    public virtual ApplicationUser PublishedBy { get; set; }


}   

}

DbContexts:

namespace MrSaleBeta01.Models
{

/*
* First (default) DbContext, points to users tables:
*/
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

...
}


/*
* Second DbContext, points to my models tables:
*/  
public class MrSaleDB : DbContext
{

    public MrSaleDB() : base("name=MrSaleDB")
    {
    }

    public DbSet<Post> Posts { get; set; }

    public DbSet<Category> Categories { get; set; }

    public DbSet<AreaCode> AreaCodes { get; set; }

    public DbSet<Gallery> Galleries { get; set; }
 ...
}       

}

PostsController:

    // POST: Posts/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize]
    public ActionResult Edit(Post post)
    {
        try
        {

            if (ModelState.IsValid)
            {

...
...
...

                //General: save post:
                db.Posts.Add(post);

                db.SaveChanges();

                return RedirectToAction("Index");
            }
        }
        catch (DbEntityValidationException ex)
        {
        }
    }
1
0
6/11/2015 4:31:01 PM

Popular Answer

So I want to answer my own question based on the excellent help I got here (stackoverflow is a life saver.. ):

1) I followed @ Steve Greene and Derek suggestion for not having 2 dbcontexts but to merge them to one which inherit from IdentityContext in the following steps:

1A) Deleting any old migrations and dbs

1B) In Web.config file, under connectionStrings element: remove the 2 lines of the old connectionStrings and add your new connectionString as follow:

    <connectionStrings>
<add name="SaleConn" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=SaleConn; Integrated Security=True; MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
    </connectionStrings>

1C) Merge the 2 dbcontexts into one class as this:

namespace MrSaleBeta01.Models
{

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

...

public DbSet<Post> Posts { get; set; }

public DbSet<Category> Categories { get; set; }

public DbSet<AreaCode> AreaCodes { get; set; }

public DbSet<Gallery> Galleries { get; set; }
...
}       

}

2) Establishing one-to-many relationship by adding to the ApplicationUser class this property:

public virtual ICollection<Post> Posts { get; set; }

and by adding to my model class (Post) the following properties:

    [ForeignKey("ApplicationUser")]
    public string ApplicationUserId { get; set; }
    public virtual ApplicationUser ApplicationUser { get; set; }

3) Enabling Migrations for project by writing to the PM console:

>Enable-Migrations
>add-migration init
>update-database 

4) In the Post controller add using Microsoft.AspNet.Identity; for enabling you to get the user-id in the next step. more info..

5) Update the Create method of the Post controller for saving the user id to the new post:

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize]
    public ActionResult Create( Post post)
    {
        try
        {

            if (ModelState.IsValid)
            {

                post.ApplicationUserId = User.Identity.GetUserId();
...
...
...

            }
        }
    }

6) Update the Edit method of the Post controller to check whether the current user is the owner of the edited post:

    [Authorize]
    public ActionResult Edit(int? id)
    {

        try
        {

            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Post post = db.Posts.Find(id);

            if (post == null)
            {
                return HttpNotFound();
            }

            if(  !User.IsInRole("Admin") && (post.ApplicationUserId != User.Identity.GetUserId()) )
            {
                return RedirectToAction("Index");
            }
....
  }
 }
}

That's it. thanks again for everyone here. You helped me so much (-;

0
5/23/2017 10:26:44 AM


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