How to add values to 2 table then map foreign key from one table to another table in Entity Framework Core using Postgresql? - c#

Here is another issue I have faced in ASP.NET Core
Let say I have 2 Tables:
Accommodation
( ID, Name, LocationID)
Location
(ID, Address, Latitude, Longitude)
And I have a form:
Name:
Address:
Latitude:
Longitude:
Then when a button is clicked I want the value to be updated on both table and also MAP the LocationID to Accommodation table
How should I code it in EF Core? Like a proper way

You could try the following example I made :
Accommodation Model and Location Model
public class Accommodations
{
public int ID { get; set; }
public string Name { get; set; }
public int LocationID { get; set; }
[ForeignKey("LocationID")]
public Location Location { get; set; }
}
public class Location
{
public int ID { get; set; }
public string Address { get; set; }
//other stuff you want
}
DbSet two model in DbContext
public class MVCDbContext:DbContext
{
public MVCDbContext(DbContextOptions<MVCDbContext> options) : base(options)
{ }
public DbSet<Accommodations> Accommodations { get; set; }
public DbSet<Location> Location { get; set; }
}
The design of the view ,pay attention to the asp-for of the input tag
#model MVC2_1Test.Models.Accommodation.Accommodations
#{
ViewData["Title"] = "Accommondation";
}
<h2>Accommondation</h2>
<div class="row">
<div class="col-md-4">
<form id="form" class=".has-error" asp-action="CreateAccommodation">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group ">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" id="cusName" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Location.Address" class="control-label"></label>
<input asp-for="Location.Address" class="form-control" id="age" />
<span asp-validation-for="Location.Address" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
The action to update both table
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateAccommodation([FromForm]Accommodations accommodation)
{
if (ModelState.IsValid)
{
_context.Add(accommodation);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(accommodation);
}

Related

displaying the input box for a different model

I have following two model classes:
public partial class EmployeeInfo
{
public string LastName { get; set; } = null!;
public string FirstName { get; set; } = null!;
public virtual ICollection<EmergencyInfo> EmergencyInfos { get; } = new List<EmergencyInfo>();
}
public partial class EmergencyInfo
{
public string emailAddress { get; set; } = null!;
public string PhoneNumber { get; set; } = null!;
public virtual EmployeeInfo EmployeeInfo { get; set; } = null!;
}
My Razor view to create a new employee looks like this:
#model AckPackage.Models.EmployeeInfo
#{
ViewData["Title"] = "Create";
}
<div class="form-group row">
<div class="col-sm-4">
<label asp-for="LastName" class="control-label"></label>
<input asp-for="LastName" class="form-control input-lg" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="col-sm-4">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control input-lg" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
</div>
Can I display the input box for emeregencyInfo, emailAddress and phone number in above view. I want to show both the input box for emailAddress and PhoneNumber in the same EmployeeInfo view so that users can input their information.
Any help will be highly appreciated.
You can create a compound class and pass it to the view as data model:
public class Info
{
public EmployeeInfo? Employee { get; set; }
public EmergencyInfo? Emergency { get; set; }
}
The view code:
#model Info;
#{
ViewData["Title"] = "Create";
}
<form method="post" asp-action="Create">
<div class="form-group row">
<div class="col-sm-4">
<label asp-for="#Model.Employee.LastName" class="control-label"></label>
<input asp-for="#Model.Employee.LastName" class="form-control input-lg" />
<span asp-validation-for="#Model.Employee.LastName" class="text-danger"></span>
</div>
...
<button type="submit">Save</button>
</form
On the controller side:
[HttpPost]
public IActionResult Create(Info data)
{
// Processing the entered data
....
return View(data);
}

ASP.NET Tag helpers and Bootstrap Dropdown. How to use together?

Faced such peculiar problem. For a better understanding, I will try to describe in more detail.
I have two metod in ArticleController:
[HttpGet]
public async Task<IActionResult> Create()
{
var sources = await _sourceServices.GetSourceNameAndId();
var listSources = new List<SourceNameAndIdModel>();
foreach (var source in sources)
{
listSources.Add(_mapper.Map<SourceNameAndIdModel>(source));
}
var viewModel = new ArticleCreateViewModel()
{
SourceNameAndIdModels = listSources
};
return View(viewModel);
}
[HttpPost]
public async Task<IActionResult> Create(ArticleCreateViewModel viewModel)
{
await _articleService.CreateArticle(_mapper.Map<ArticleDTO>(viewModel));
return RedirectToAction("Index", "Article");
}
As you can see, in the Get-method, I get the names and ids of all Sources from the database via _sourceService in the form of IEnumerable :
public class SourceNameAndIdDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
}
Next, I enumerate them in a foreach loop and add each SourceNameAndIdDTO object to the List listSources I created before:
public class SourceNameAndIdModel
{
public string Name { get; set; }
public Guid Id { get; set; }
}
Next, I create an instance of the ArticleCreateViewModel model, which I will use further in the View:
public class ArticleCreateViewModel
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Title { get; set; }
public string Description { get; set; }
public string Body { get; set; }
public Guid SourceId { get; set; }
public DateTime CreationDate { get; set; }
public List<SourceNameAndIdModel> SourceNameAndIdModels { get; set; }
}
And I assign to the field public List SourceNameAndIdModels { get; set; } List listSources values:
var viewModel = new ArticleCreateViewModel()
{
SourceNameAndIdModels = listSources
};
You can see this in the controller code I posted above. Next, I send the viewModel to the View.
Code of my View:
#model ArticleCreateViewModel
<div class="container">
<h2>Edit article</h2>
<div class="row gx-5">
<form asp-controller="Article" asp-action="Create" asp-antiforgery="true" method="post">
<div>
<input type="hidden" asp-for="Id" />
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="Title"></label>
<input class="form-control" type="text" asp-for="Title">
</div>
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="Description"></label>
<textarea class="form-control" asp-for="Description"></textarea>
</div>
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="Body"></label>
<textarea class="form-control" asp-for="Body"></textarea>
</div>
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Source
</a>
<ul class="dropdown-menu">
#foreach (var item in #Model.SourceNameAndIdModels)
{
<li><select class="dropdown-item" asp-for="SourceId" asp-items="#item.Id">#item.Name</select></li>
}
</ul>
</div>
<div class="mb-3">
<label class="col-sm-2 col-form-label" asp-for="CreationDate"></label>
<input type="datetime-local" class="form-control" asp-for="CreationDate">
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
And finally, in this place of the code, in which I want to set the Source of the article I am creating, I have an error:
enter image description here
Can you please tell me how in my case to make friends with my code with dropdown on my request? What am I doing wrong?
Using asp-items in this way is incorrect.
The Select Tag Helper asp-items specifies the option elements
Details and example:
https://learn.microsoft.com/...netcore-6.0#the-select-tag-helper

Why File upload is stopped working after convert multiple models into a view model entity framework?

Controller
public async Task<IActionResult> Create(IFormFile? StaffPhoto, CollectionViewModel collectionModel)
{
if (StaffPhoto != null){...} // issue is StaffPhoto value is null
}
View Model
namespace Website.Models
{
public class CollectionViewModel
{
public Staff staff { get; set; }
public Contact contact { get; set; }
}
}
Entity Model
public class Staff
{
public int StaffId { get; set; }
[DisplayName("First Name")]
[Required]
public string StaffFirstName { get; set; }
[DisplayName("Last Name")]
[Required]
public string StaffLastName { get; set; }
[DisplayName("Photo")]
public string? StaffPhoto { get; set; }
}
View
#model CollectionViewModel
<form asp-action="Create" enctype="multipart/form-data" method="post" class="row g-3 mt-0">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="col">
<label asp-for="staff.StaffFirstName" class="form-label"></label>
<input asp-for="staff.StaffFirstName" class="form-control" />
<span asp-validation-for="staff.StaffFirstName" class="text-danger"></span>
</div>
<div class="col">
<label asp-for="staff.StaffLastName" class="form-label"></label>
<input asp-for="staff.StaffLastName" class="form-control" />
<span asp-validation-for="staff.StaffLastName" class="text-danger"></span>
</div>
<div class="col-md-3">
<label asp-for="staff.StaffPhoto" class="form-label"></label>
<input asp-for="staff.StaffPhoto" type="file" accept="image/*" class="form-control" />
<span asp-validation-for="staff.StaffPhoto" class="text-danger"></span>
#{if (ViewBag.fileUploadErrorMessage != null)
{
<span class="text-danger">#ViewBag.fileUploadErrorMessage</span>
}
}
</div>
<div class="col">
<input type="submit" value="Create" class="btn btn-primary" />
<a asp-action="Create" class="btn btn-secondary">Reset All</a>
</div>
</form>
You should add IFormFile in model.
public class CollectionViewModel
{
public Staff staff { get; set; }
public IFormFile StaffPhoto { get; set; }
public Contact contact { get; set; }
}
set StaffPhoto to asp-for in view.
<input asp-for="StaffPhoto" type="file" accept="image/*" class="form-control" />

How to populate dropdown list from nested Models? (Asp.net Core MVC)

I have a nested model and I use one model named (BootstrapTool) to make the view strongly typed.
I use ViewBag to populate a dropdown list with the nested Model named (BootstrapCategory). But my problem is when I select from it always returns validation null exception.
BootstrapTool Model
public class BootstrapTool
{
public Guid Id { get; set; }
[MaxLength(100,ErrorMessage ="Max 100")]
[Required]
public string tool { get; set; }
[MaxLength(300, ErrorMessage = "Max 300")]
[Required]
public string descreption { get; set; }
[Required]
public string html { get; set; }
[Required] // here where nisting the other Model BootstrapCategory
public BootstrapCategory category { get; set; }
}
BootstrapCategory Model
public class BootstrapCategory
{
[Key]
public Guid Id { get; set; }
[MaxLength(20)]
[Required]
public string Category { get; set; }
}
The Controller
public IActionResult Create()
{
List<BootstrapCategory> bootstrapCategories = _context.bootstrapCategories.ToList();
ViewBag.bpCategories = new SelectList(bootstrapCategories, "Id", "Category");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(BootstrapTool bootstrapTool)
{
if (ModelState.IsValid)
{
bootstrapTool.Id = Guid.NewGuid();
_context.Add(bootstrapTool);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(bootstrapTool);
}
Here where the dropdown list is to display BootstrapCategory
The View
#model BootstrapTool
<div class="row">
<div class="col-10 offset-1">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="gap-2 d-flex justify-content-between">
<div class="form-group w-50">
<label asp-for="tool" class="control-label"></label>
<input asp-for="tool" class="form-control" />
<span asp-validation-for="tool" class="text-danger"></span>
</div>
<div class="form-group w-50">
<label class="control-label">category</label>
<select asp-for="category.Id" class="form-control" asp-items="#ViewBag.bpCategories">
<option value="" disabled hidden selected>Select Section ...</option>
</select>
<span asp-validation-for="category" class="text-danger"></span>
#*<select asp-for="Id" asp-items="#Html.GetEnumSelectList<Enum>()" class="form-control">
<option value="" hidden disabled selected> -- please selecgt -- </option>
</select>*#
</div>
</div>
<div class="form-group">
<label asp-for="descreption" class="control-label"></label>
<textarea asp-for="descreption" class="form-control" rows="2"></textarea>
<span asp-validation-for="descreption" class="text-danger"></span>
</div>
<div class="form-group mb-2">
<label asp-for="html" class="control-label"></label>
<textarea asp-for="html" class="form-control" rows="5"></textarea>
<span asp-validation-for="html" class="text-danger"></span>
</div>
<div class="form-group mt-3">
<input type="submit" value="Create" class="btn btn-primary d-grid col-6 mx-auto" />
</div>
</form>
</div>
</div>
Add CategoryId
public class BootstrapTool
{
[Key]
public Guid Id { get; set; }
[Required]
public Guid? CategoryId { get; set; }
[ForeignKey(nameof(CategoryId))]
[InverseProperty("BootstrapTools")]
public BootstrapCategory Category { get; set; }
}
public class BootstrapCategory
{
[Key]
public Guid Id { get; set; }
[MaxLength(20)]
[Required]
public string Category { get; set; }
[InverseProperty(nameof(BootstrapTool.Category))]
public virtual ICollection<BootstrapTool> BootstrapTools { get; set; }
}
and fix the view
<select asp-for="CategoryId" class="form-control" asp-items="#ViewBag.bpCategories">
</select>
```

ASP.NET MVC View needs to display data from a certain model and at the same time take input data for another model

I have a View which uses a dynamic object to pull data from multiple models declared in the ViewModel. However, within the same model I am trying to take user input via a form. The data is correctly displayed for the 2 models which are also part of the dynamic object. But I am UNSUCCESSFUL getting the form input, because I keep getting the error that the dynamic object is not accessible.[And this is for the form only.]
Here is how the View looks like
#model dynamic
#using ActionAugerMVC.ViewModels
#addTagHelper "*,Microsoft.AspNetCore.Mvc.TagHelpers"
<div class="course__title">
#Model.item.PageTitle
</div>
<p class="course__desc">
#Html.Raw(Model.item.PageText)
</p>
<div class="event__price">
<h3>#Model.item.NoticeTitle</h3>
<p>#Model.item.NoticeNeedItem</p>
<button type="submit" class="btn btn-accent">
Get A Quote Now
</button>
</div>
<h3 class="course_desc__title">Other Services</h3>
<ul class="course_requirements__list multi-column">
#foreach (var link in Model.data)
{
<li><i class="ion-android-arrow-forward"></i> #Html.ActionLink((string)link.PageTitle, "Page", "Plumbing", new { id = link.ID, url = link.PageURL }) </li>
}
</ul>
<div class="sidebar__item">
<p class="subheading">Instant Quote Request</p>
<form class="register__form" role="form" asp-controller="Plumbing" asp-action="Page" method="post">
<div class="text-danger" asp-validation-summary="All"></div>
<div class="form-group">
<label class="sr-only">Full Name </label>
<input asp-for="#Model.quote.FullName" type="text" class="form-control" placeholder="Full name">
</div>
<div class="form-group">
<label class="sr-only">Your phone</label>
<input asp-for="#Model.quote.Phone" type="tel" class="form-control" placeholder="Your phone">
<span asp-validation-for="#Model.quote.Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">E-mail</label>
<input asp-for="#Model.quote.Email" type="email" class="form-control" placeholder="E-mail">
<span asp-validation-for="#Model.quote.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label class="sr-only">Your Message</label>
<input asp-for="#Model.quote.Message" type="text" class="form-control" placeholder="Your Message">
</div>
<input type="submit" value="Get a Quote Now" class="btn btn-accent btn-block">
</form>
</div> <!-- .sidebar__item -->
And here is how the controller looks like :-
public class PlumbingController : Controller
{
private readonly ActionAugerDataContext actionAugerDbContext;
private readonly UnitOfWork unitOfWork;
private readonly PlumbingPageViewModel plumbingViewModel;
public PlumbingController(ActionAugerDataContext context)
{
actionAugerDbContext = context;
unitOfWork = new UnitOfWork(actionAugerDbContext);
plumbingViewModel = new PlumbingPageViewModel(unitOfWork);
}
// GET: /<controller>/
public IActionResult Index()
{
var data = plumbingViewModel.PlumbingContent;
return View(data);
}
[HttpGet]
[Route("plumbing/calgary-{url}")]
public IActionResult Page(int ID, string url)
{
dynamic Page = new ExpandoObject();
Page.item = unitOfWork.ContentRepository.GetById(ID);
Page.data = plumbingViewModel.PlumbingContent;
Page.cities = plumbingViewModel.Cities;
// Page.quote = plumbingViewModel.Quote;
return View(Page);
}
[HttpPost]
public IActionResult Page(Quote quote)
{
return View();
}
}
Here is the View Model :-
public class PlumbingPageViewModel
{
public IEnumerable<Content> PlumbingContent { get; set; }
public IEnumerable<Cities> Cities { get; set; }
public Quote Quote { get; set; }
public PlumbingPageViewModel(UnitOfWork unitOfWork)
{
PlumbingContent = unitOfWork.ContentRepository
.GetAll()
.Where(d => d.Section == "Plumbing")
.Where(c => c.City == "Calgary");
Cities = unitOfWork.CitiesRepository
.GetAll()
.Where(c => c.HomeCity == "Calgary");
}
}
And here is the model class for the form.
public class Quote
{
public int ID { get; set; }
public string FullName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string City { get; set; }
public string Message { get; set; }
}
you can't you use dynamic model ( #model dynamic) for building your form with HtmlHelper
If you want Post form you should specific model.
Hope you this will you.

Categories