Home > other >  One-To-Many relationship between ApplicationUser and an other object
One-To-Many relationship between ApplicationUser and an other object

Time:03-12

I am struggling trying to implement à create action and an index for my controller.

Basically, I want each user to have multiple pizzas.

I want the connected user to create his own pizzas.

And in the index of my controller I want to show, only the pizzas created by the current connected user.

Here are my models :

1/Pizzas :

public class PizzaModel
    {
        [Key]
        public int PizzaID { get; set; }

        [Display(Name = "Nom")]
        public string nom { get; set; }
        [Display(Name = "Prix(€)")]
        public float prix { get; set; }
        [Display(Name = "Végétarienne")]
        public bool vegetarienne { get; set; }
        [Display(Name = "Ingrédients")]
        public string ingredients { get; set; }

       
       
        public virtual ApplicationUser ApplicationUser { get; set; }

        
        public string ApplicationUserId { get; set; }

    }

2/ ApplicationUser :

public class ApplicationUser : IdentityUser
    {
        public ICollection<PizzaModel> Pizzas { get; set; }
    }

3/ This is my Context :

public class AuthDbContext : IdentityDbContext<ApplicationUser>
    {
        public AuthDbContext(DbContextOptions<AuthDbContext> options) : base(options)
        {

        }

        public DbSet<PizzaModel> Pizzas { get; set; }

        public DbSet<ApplicationUser> ApplicationUsers { get; set; }    

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<ApplicationUser>()
                .HasMany(p => p.Pizzas)
                .WithOne(u => u.ApplicationUser)
                .IsRequired()
                .HasForeignKey(p => p.ApplicationUserId);

            base.OnModelCreating(builder);
        }

I want to create a "create action" and an "index action" that shows only the pizzas created by the current connected user. Here is what I have done so far :

1/ Index action method :

public async Task<IActionResult> Index(string searchByName)
        {

            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);

            IEnumerable<PizzaModel> pizzas = new List<PizzaModel>();
            
            pizzas = _context.Pizzas.Where(x => x.ApplicationUserId == userId);
            

            return View(pizzas);
        }

2/ Create Action Method :

public async Task<IActionResult> Create(PizzaModel model)
        {

                _context.ApplicationUsers.Add(model);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index), "Pizza");
                
        }

Could you please help me with these 2 actions (Create and Index) ?

CodePudding user response:

According to your Model and DbContext, I create the actions as below: I'm using the Home Controller and Project name is "WebApplication3"

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly ApplicationDbContext _dbContext;

    public HomeController(ILogger<HomeController> logger, ApplicationDbContext dbContext)
    {
        _logger = logger;
        _dbContext = dbContext;
    }

    public IActionResult Index()
    {
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        
        IEnumerable<PizzaModel> pizzas = new List<PizzaModel>();

        pizzas = _dbContext.Pizzas.Where(x => x.ApplicationUserId == userId);
         
        return View(pizzas);
    }


    public IActionResult Create()
    {
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Create(PizzaModel model)
    {
        //Note: if you check the ModelState.IsValid, it will return false, because there is no ApplicationID and PizzaID,
        //you can create a view model to enter the new value, then, convert it to PizzaModel
        //validate the model
        //if (ModelState.IsValid)
        //{
        //get current user id
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);

            if (userId != null)
            {
                //based on the userid to find current user and get its pizzas.
                var currentuser = _dbContext.ApplicationUsers.Include(c => c.Pizzas).First(c => c.Id == userId);
                List<PizzaModel> pizzas = new List<PizzaModel>();
                pizzas = currentuser.Pizzas.ToList();

                //add the new item to pizza list
                pizzas.Add(new PizzaModel()
                {
                    nom = model.nom,
                    prix = model.prix,
                    vegetarienne = model.vegetarienne,
                    ingredients = model.ingredients
                });
                //update the pizzas for current user.
                currentuser.Pizzas = pizzas;
                await _dbContext.SaveChangesAsync();
            }

            return RedirectToAction(nameof(Index));
        //}
        //else
        //{
        //    return View();
        //}
    }

The Index view as below:

@model IEnumerable<WebApplication3.Data.PizzaModel>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>


<table >
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.PizzaID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.nom)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.prix)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vegetarienne)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ingredients)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ApplicationUserId)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @if(Model.ToList().Count > 0)
        {
            @foreach (var item in Model) {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.PizzaID)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.nom)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.prix)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.vegetarienne)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.ingredients)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.ApplicationUserId)
                    </td>
                    <td>
                        @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                        @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                        @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
                    </td>
                </tr>
            }
        }
        else
        {
            <tr><td colspan="7">Empty</td></tr>
        }

    </tbody>
</table>

<p>
    <a asp-action="Create">Create New Pizza</a>
</p>

The Create View:

@model WebApplication3.Data.PizzaModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>PizzaModel</h4>
<hr />
<div >
    <div >
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" ></div> 
            <div >
                <label asp-for="nom" ></label>
                <input asp-for="nom"  />
                <span asp-validation-for="nom" ></span>
            </div>
            <div >
                <label asp-for="prix" ></label>
                <input asp-for="prix"  />
                <span asp-validation-for="prix" ></span>
            </div>
            <div >
                <label >
                    <input  asp-for="vegetarienne" /> @Html.DisplayNameFor(model => model.vegetarienne)
                </label>
            </div>
            <div >
                <label asp-for="ingredients" ></label>
                <input asp-for="ingredients"  />
                <span asp-validation-for="ingredients" ></span>
            </div> 
            <div >
                <input type="submit" value="Create"  />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

The result as below:

enter image description here

Generally, in the HttpPost method such as the Create or Update action method, we need to validte the model is valid or not, then based on the result to show validation message or go the next steps. You can refer the following tutorials:

Model validation in ASP.NET Core MVC and Razor Pages

Tutorial: Implement CRUD Functionality - ASP.NET MVC with EF Core

  • Related