I have 2 models with one to many relationship and want to make drop down list Model 1 View Page and there is my code:
Model 1
public class Events
{
public Guid Id { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.ResourceData), ErrorMessageResourceName = "EventName")]
[MaxLength(80, ErrorMessageResourceType = typeof(Resources.ResourceData), ErrorMessageResourceName = "MaxLength")]
[MinLength(8, ErrorMessageResourceType = typeof(Resources.ResourceData), ErrorMessageResourceName = "MinLength")]
public string Name { get; set; }
public Guid EventsCategoriesId { get; set; }
[ForeignKey("EventsCategoriesId")]
public EventsCategories EventsCategories { get; set; }
}
Model 2
public class EventsCategories
{
public Guid Id { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.ResourceData), ErrorMessageResourceName = "CategoryName")]
[MaxLength(50, ErrorMessageResourceType = typeof(Resources.ResourceData), ErrorMessageResourceName = "MaxLength")]
[MinLength(5, ErrorMessageResourceType = typeof(Resources.ResourceData), ErrorMessageResourceName = "MinLength")]
public string Name { get; set; }
}
Project DbContext file:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Events>()
.Property(x => x.Id).HasDefaultValueSql("(newid())");
builder.Entity<EventsCategories>()
.Property(x => x.Id).HasDefaultValueSql("(newid())");
}
public DbSet<Events> events { get; set; }
public DbSet<EventsCategories> eventsCategories { get; set; }
IServicesRepository file:
public interface IServicesRepository<T> where T : class
{
List<T> GetAll();
T FindBy(Guid Id);
bool Save(T model);
bool Delete(Guid Id);
}
Services file for events:
public class ServicesEvents : IServicesRepository<Events>
{
private readonly ProjectDBContext _context;
public ServicesEvents(ProjectDBContext context)
{
_context = context;
}
public bool Delete(Guid Id)
{
}
public Events FindBy(Guid Id)
{
try
{
return _context.events
.Include(x => x.EventsCategories)
.FirstOrDefault(x => x.Id.Equals(Id));
}
catch (Exception)
{
return null;
}
}
public List<Events> GetAll()
{
try
{
return _context.events
.Include(x => x.EventsCategories)
.OrderBy(x => x.Name).ToList();
}
catch (Exception)
{
return null;
}
}
public bool Save(Events model)
{
try
{
var result = FindBy(model.Id);
if (result == null)
{
model.Id = Guid.NewGuid();
_context.events.Add(model);
}
else
{
result.Name = model.Name;
result.EventsCategoriesId = model.EventsCategoriesId;
_context.events.Update(result);
}
_context.SaveChanges();
return true;
}
catch (Exception)
{
return false;
}
}
}
Events view model:
public class EventsViewModel
{
public List<Events> events { get; set; }
public Events NewEvents { get; set; }
}
Events controller:
public class EventsController : Controller
{
private readonly IServicesRepository<Events> servicesEvents;
public EventsController(IServicesRepository<Events> servicesEvents)
{
this.servicesEvents = servicesEvents;
}
public IActionResult Events()
{
return View(new EventsViewModel
{
events = _servicesEvents.GetAll(),
NewEvents = new Events()
});
}
[HttpPost]
[AutoValidateAntiforgeryToken]
public IActionResult Save(EventsViewModel model)
{
if (ModelState.IsValid)
{
if (model.NewEvents.Id == Guid.Parse(Guid.Empty.ToString()))
{
// Save
if (_servicesEvents.FindBy(model.NewEvents.Name) != null)
SessionMsg.....;
else
{
if (_servicesEvents.Save(model.NewEvents))
SessionMsg......;
else
SessionMsg.......;
}
}
else
{
// Update
if (_servicesEvents.Save(model.NewEvents))
SessionMsg..........;
else
SessionMsg..........;;
}
}
return RedirectToAction(nameof(Events));
}
}
Events view on get:
<table >
<thead>
<tr>
<td>Name</td>
<td>Category Id</td>
</tr>
</thead>
<tbody>
@foreach (var item in Model.events)
{
<tr>
<td>
@item.Name
</td>
@item.EventCategories.Id
</td>
</tr>
}
</tbody>
</table>
On Post form:
<form asp-action="Save" asp-controller="Events" method="post" enctype="multipart/form-data">
<div class="form-group">
<label asp-for="NewEvents.Name" class="control-label">Name</label>
<input type="text" class="form-control" asp-for="NewEvents.Name" />
<span asp-validation-for="NewEvents.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NewEvents.CategoryId" class="control-label">Category/label>
<select class="custom-select-sm" asp-for="NewEvents.CategoryId" asp-items="@(new SelectList(Model.NewEvents.EventCategories,"Id","Name"))">
<option value="">Category</option>
</select>
<span asp-validation-for="NewEvents.CategoryId" class="text-danger"></span>
</div>
</form>
I'm trying to run this code and always get errors or get list without items
Actually, your EventsViewModel defination is inconsistent as per your view which causing the error or empty data. Its not seen how you are calling eventsCategories list while loading the view.
I am not using your repository snippet. Thus, just simplifying the implementation for a quick demo. You could try in following way:
EventsViewModel:
Event Index Controller Action:
Note: Getting the event Categories you can set where clause to implement your foreign key constrain filter.
View:
Output:
Note: If you would like to know more details on Select Tag Helper you could check our official document here.