concatenate two fields in drop down list - asp.net

I have a model class
namespace myapp.Models
{
public class SubjectModels
{
[Key]
public int SubjectId { get; set; }
[Required]
public int SubjectType { get; set; }
[Required]
[MinLength(5)]
public string SubjectName { get; set; }
}
}
Here, SubjectType = 1 for Optional and SubjectType = 2 for Compulsory
Now in another class I have to create a drop down for this class,
namespace myapp.Models
{
public class SelectionModels
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int SelectionId { get; set; }
[Required]
[MinLength(5)]
public string SelectionDate { get; set; }
[ForeignKey("SubjectId")]
public SubjectModels Subject { get; set; }
public int SubjectId { get; set; }
}
}
When I genereted controller and create.cshtml via scaffolding, my create controller method:
public ActionResult Create()
{
ViewBag.SubjectId = new SelectList(db.Subjects, "SubjectId", "SubjectName");
return View();
}
But I have to create a drop down concatenating the fields "SubjectName" and "SubjectType". Also, display for SubjectType should be Optional and Compulsory not integer.
for example,
"Optional - ResearchMethodology"
"Compulsory - BioChemistry"
How shall I do this? I googled but could not found suitable solutions. Please help!!!

I would create an extra property in the SubjectModels class.
class SubjectModels
{
public int SubjectId { get; set; }
public int SubjectType { get; set; }
public string SubjectName { get; set; }
public string SubjectNameAndType
{
get
{
return string.Format("{0} - {1}", SubjectName, SubjectType);
}
}
}
Then in the Controller you can use that property to fill the SelectList
var list = new List<SubjectModels>()
{
new SubjectModels()
{
SubjectType = 1,
SubjectName = "Name 1"
},
new SubjectModels()
{
SubjectType = 2,
SubjectName = "Name 2"
}
};
ViewBag.SubjectId = new SelectList(list, "SubjectId", "SubjectNameAndType");
Now you will see the correct values in the DropDownList.
#Html.DropDownListFor(m => m.MyValue, (SelectList)ViewBag.SubjectId, "Select...")

Related

How to create a drop-down in asp.net core MVC from another Model with validation?

Model Class.cs
public class Class
{
public int ClassId { get; set; }
[NotMapped]
public string EncryptedId { get; set; }
[Required]
[Display(Name = "Class Name")]
public string ClassName { get; set; }
}
Model Subject.cs
public class Subject
{
public int SubjectId { get; set; }
[NotMapped]
public string EncryptedId { get; set; }
public string SubjectName { get; set; }
public int ClassId { get; set; }
public Class Class { get; set; }
}
ViewModel CreateSubjectViewModel.cs
public class CreateSubjectViewModel
{
public int SubjectId { get; set; }
[NotMapped]
public string EncryptedId { get; set; }
[Required]
[Display(Name = "Subject Name")]
public string SubjectName { get; set; }
public int ClassId { get; set; }
public int ClassesId { get; set; }
public virtual List<Class> Classes { get; set; }
}
Controller Code
[HttpGet]
public IActionResult CreateSubject()
{
List<Class> classList = _context.Classes.ToList();
ViewData["classList"] = classList.Select(x => new SelectListItem { Value = x.EncryptedId, Text = x.ClassName });
return View();
}
[HttpPost]
public IActionResult CreateSubject(CreateSubjectViewModel model)
{
if (ModelState.IsValid)
{
Subject newSubject = new Subject
{
//SubjectName = model.SubjectName,
//here code for store data in subject table
};
_cdsRepository.AddSubject(newSubject);
return RedirectToAction("ListClasses", "UDP");
}
return View(model);
}
How can I get data from Class.cs and show in drop-down with proper validation of drop-down on button click.
If everything is OK, then store data in Subject.cs with Class Id value.

Select Max() with GroupBy, using linq method syntax, EF

I have a bunch of classes with some data:
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime bDate { get; set; }
//One-to-one with course
public int CourseId { get; set; }
public virtual Course Course { get; set; }
}
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection <Student_Course> Student_Courses { get; set; }
public int TeacherId { get; set; }
public virtual Teacher Teacher { get; set; }
}
public class Grade
{
public int Id { get; set; }
public int Mark { get; set; }
//one-to-many with Student_Course
public int Student_CourseId { get; set; }
public Student_Course Student_Course { get; set; }
}
public class Student_Course
{
public int Id { get; set; }
//many-to-many with student
public int StudentId { get; set; }
public virtual Student Student { get; set; }
//many-to-many with course
public int CourseId { get; set; }
public virtual Course Course { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime bDate { get; set; }
//one-to-many with student_course
public virtual ICollection <Student_Course> Student_Courses { get; set; }
}
Now i trying to write a query - for everyone teacher(name) needs to output his best student(name) by student mark, and the best mark, from class Grades, my code:
public IActionResult Task9()
{
var task9 = Db.Grades.GroupBy(gr => gr.Student_Course.Course.Teacher.Name).Select(x => new Task9
{
NameOfSt = x.Select(st => st.Student_Course.Student.Name).FirstOrDefault(),//Needs to correct this line
NameOfTeac = x.Select(r => r.Student_Course.Course.Teacher.Name).FirstOrDefault(),
BestMark = x.Max(gr => gr.Mark)
//NameOfSt = Db.Students.FirstOrDefault(st => st.Id ==x.FirstOrDefault().Student_Course.StudentId).Name
});
return View(task9);
}
So that code output correct teacher name and best mark on the course from students. But the student name is actually wrong. How can i fix that? Thanks for any help.
Teac
BestMark
NameStud
You could use OrderByDescending by Mark before select student name:
var task9 = Db.Grades.GroupBy(gr => gr.Student_Course.Course.Teacher.Name).Select(x => new Task9
{
NameOfSt = x.OrderByDescending(st => st.Mark).Select(st => st.Student_Course.Student.Name).FirstOrDefault(),//Needs to correct this line
NameOfTeac = x.Select(r => r.Student_Course.Course.Teacher.Name).FirstOrDefault(),
BestMark = x.Max(gr => gr.Mark)
});
Within the GroupBy you need to use the value of the grouping (in this case x) to select the Grade object with the highest Grade. In the code below, I get the bestGrade object by ordering by the Mark in descending order and then taking the first entry and then I take the student, name and best mark from that object:
public IActionResult Task9()
{
var task9 = Db.Grades.GroupBy(gr => gr.Student_Course.Course.Teacher.Name).Select(x =>
{
var bestGrade = x.OrderByDescending(y => y.Mark).First();
return new Task9
{
NameOfSt = bestGrade.Student_Course.Student.Name,//Needs to correct this line
NameOfTeac = bestGrade.Student_Course.Course.Teacher.Name,
BestMark = bestGrade.Mark
};
});
return View(task9);
}

AutoMapper with auto-incremented values

public class OrderDTO
{
public string ClientName { get; set; }
public ICollection<OrderDetailDTO> Details { get; set; }
}
public class Order
{
public string ClientName { get; set; }
public ICollection<OrderDetail> Details { get; set; }
}
public class OrderDetailDTO
{
public int Quantity { get; set; }
public string ProductName { get; set; }
}
public class OrderDetail
{
public int OrderId { get; set; }
public int Quantity { get; set; }
public string ProductName { get; set; }
}
Let's say there are 4 OrderDetailDTO, I want to have the mapped OrderDetail instances with auto-incremented integer values. What I am doing now is post-process the mapped instance.
var mappedOrder = Mapper.Map<OrderDTO, Order>(orderDto);
var orderId = 1;
foreach (OrderDetail detail in mappedOrder.Details)
{
detail.OrderId = orderId++;
}
How can I configure the mapping options, so that the mapped ICollection<OrderDetail> contains 4 OrderDetail instances with OrderId as 1, 2, 3, 4?
You could configure AutoMapper to do this with AfterMap:
Mapper.CreateMap<OrderDTO, Order>()
.AfterMap((src, dest) =>
{
int orderId = 1;
foreach (OrderDetail detail in dest.Details)
{
detail.OrderId = orderId++;
}
});
I don't think there's really a "cleaner" way to do it using AutoMapper.
I use the following method which is much simpler and can be written in a base class or an extension method. The example here uses Generics but can be easily transformed
protected virtual IEnumerable<T> ConvertCsvLines(IEnumerable<TV> lines)
{
var lineNumber = 0;
return lines.Select(x =>
{
var retVal = Mapper.Map<TV, T>(x);
retVal.LineNumber = lineNumber++;
return retVal;
});
}

MVC 5 Multiple Models in a Single View

Could somebody please provide an example of how to combine two models within one view?
Currently I have a page called RecordCard which contains:
#model IEnumerable<WebApplication1.Models.Weight>
This is provided by the following code in the AccountController:
public ActionResult RecordCard()
{
var UserId = User.Identity.GetUserId();
var weightModel = from m in db.Weights where m.UserId == UserId select m;
return View(weightModel);
}
The RecordCard page also contains a form which is bound to the following class:
public class AddWeightModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "Stone")]
public Nullable<short> Stone { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Pound")]
public Nullable<short> Pound { get; set; }
}
However, these are two individual models with different purposes, so how do I combine to a single model that contains an IEnumerable list and set of form elements that will ultimately post to the AccountController correctly to add a record to the database using the following code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RecordCard(Weight Model)
{
if (ModelState.IsValid)
{
using (WebApplication1Entities db = new WebApplication1Entities())
{
Weight weight = new Weight();
weight.UserId = User.Identity.GetUserId();
weight.Stone = Model.Stone;
weight.Pound = Model.Pound;
weight.Date = System.DateTime.Now;
db.Weights.Add(Model);
db.SaveChanges();
}
}
return View(Model);
}
I have included the Weight class below:
public partial class Weight
{
public int Id { get; set; }
public string UserId { get; set; }
public Nullable<short> Stone { get; set; }
public Nullable<short> Pound { get; set; }
public Nullable<System.DateTime> Date { get; set; }
}
Also here is the WebApplication1Entities class which declares the Weight table as Weights:
public partial class WebApplication1Entities : DbContext
{
public WebApplication1Entities()
: base("name=WebApplication1Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Weight> Weights { get; set; }
}
Please explain what needs to be modified and how, no matter what I try to read, follow and implement, I seem to be missing something.
Any help would be much appreciated :-)
I would say this is good example of using ViewModel here. I would suggest something like -
Create ViewModel with the composition of the two classes
public class AddWeightModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "Stone")]
public Nullable<short> Stone { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Pound")]
public Nullable<short> Pound { get; set; }
}
....
public partial class Weight
{
public int Id { get; set; }
public string UserId { get; set; }
public Nullable<short> Stone { get; set; }
public Nullable<short> Pound { get; set; }
public Nullable<System.DateTime> Date { get; set; }
}
.....
public class WeightViewModel
{
public IList<AddWeightModel> AddWeightModel { get; set; }
public Weight Weight { get; set; }
}
Then change your view to accept the view models -
#model WeightViewModel
Finally modify your controller to cope with the change -
public ActionResult RecordCard()
{
var UserId = User.Identity.GetUserId();
var weightModel = from m in db.Weights where m.UserId == UserId select m;
var viewModel = new WeightViewModel
{
Weight = weightModel,
AddWeightModel = new List<AddWeightModel>(){}
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RecordCard(WeightViewModel viewModel)
{
Weight Model = viewModel.Weight;
if (ModelState.IsValid)
{
using (WebApplication1Entities db = new WebApplication1Entities())
{
Weight weight = new Weight();
weight.UserId = User.Identity.GetUserId();
weight.Stone = Model.Stone;
weight.Pound = Model.Pound;
weight.Date = System.DateTime.Now;
db.Weights.Add(Model);
db.SaveChanges();
}
}
return RedirectToAction("RecordCard");
}
I've tackled this before, can came to an elegant solution.
First, you'd want to setup your main classes to send, as well as a 'holder' class to store them to eventually send to a view.
As you probably found out, this is because a view can't have multiple models sent to it.
public class WebsiteTheme
{
public string Color { get;set; }
public string Title { get;set; }
public WebsiteTheme() {
Color = "blue";
Title = "test website";
}
}
public class User
{
public string Name { get;set; }
public string Gender { get;set; }
public User() {
Name = "Anonymous";
Gender = "Unspecified";
}
}
public class ToPage
{
public WebsiteTheme WebsiteTheme{ get; set; }
public User User { get; set; }
public ToPage() {
websiteTheme = new WebsiteTheme();
user = new User();
}
}
This will allow you to send any amount of classes to your page.
Then, in your controller, you'd want to populate those classes. Make sure to initialise them all first, then set the populated classes to your holder class.
WebsiteTheme websiteTheme = new WebsiteTheme();
websiteTheme.Color = "orange";
User user = new User();
user.Name = "Darren";
ToPage toPage = new ToPage();
toPage.User = user;
toPage.WebsiteTheme = websiteTheme;
return View(toPage);
In your view, you'd call them in any way you want to. But make sure to use HolderModel.SpecifiedModel in every case.
#model WebApplication1.Models.ToPage
#Html.DisplayFor(model => model.User.Name)
I did a compound model like this:
public class CompoundModel
{
public SearchModel SearchModel { get; set; }
public QueryResultRow ResultModel { get; set; }
}
public class QueryResultRow
{
[DisplayName("Id")]
public long id { get; set; }
[DisplayName("Importdatum")]
public System.DateTime importdate { get; set; }
[DisplayName("Mandant")]
public int indexBMClient { get; set; }
}
public class SearchModel
{
[Required]
[DataType(DataType.Date)]
[Display(Name = "Zeitraum von")]
public DateTime dateFrom { get; set; }
[Display(Name = "Terminal-ID")]
public string tid { get; set; }
[Display(Name = "Belegnummer")]
public string receiptnumber { get; set; }
}
In the view header:
#model MyProject_aspmvc.Models.CompoundModel
And get data access from the SearchModel, for example:
model => model.SearchModel.tid
and data access from the ResultModel, for example:
model => model.ResultModel.importdate

MVC, Entity Framework Select data from multiple models

In a ASP.NET MVC3 Razor project I have 2 Models
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Contents { get; set; }
public int Author { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Post.Author field links to Author.Id field
In a view, I need to display list of
Post.Title
Post.Contents
Author.Name
How to display the information joining (from) both models?
Note : I guess I need to use a ViewModel and bind the view with IEnumerable List, but I have no idea how to select the data from both models
You can create a viewmodel which will have ONLY properties which u want to be displayed on view
public class PostViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Contents { get; set; }
public string AuthorName { get; set; }
}
You populate this viewmodel with your data in your controller action taking necessary joins
public ActionResult GetAuthorInfor()
{
var query = //context.Post join with context.Author
Select new PostViewModel()
{
Id = post.id,
Title = post.title,
Contents = post.contents,
AuthorName = author.authorname
}
return view(query.Single());
}
and create a typed view to render this model.
Model Post.cs:
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Contents { get; set; }
public int AuthorID { get; set; }
public virtual Author Author { get; set; }
}
Model Author.cs :
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
DBContext Class:
public class SampleDB : DbContext
{
public DbSet<Author> Authors{ get; set; }
public DbSet<Post> Posts{ get; set; }
}
I.Way(using direkt view)
you can use on View like this :
Samp.Models.SampleDB dbPosts = new Samp.Models.SampleDB();
foreach (var post in dbPosts.Posts.ToList())
{
string post_Title = post.title;
string post_Contents = post.Contents;
string author_Name = post.Author.Name;
}
II.Way (Using via Controller) -Recommended-
you can use on Controller like this :
Samp.Models.SampleDB db = new Samp.Models.SampleDB();
public ActionResult Index()
{
return View(db.Posts.ToList());
}
Using this on View:
#model IEnumerable<Samp.Models.Post>
foreach (var post in Model.Posts.ToList())
{
string post_Title = post.title;
string post_Contents = post.Contents;
string author_Name = post.Author.Name;
}

Resources