I have the following entity model:
public class Project
{
[Key]
public int ProjectID { get; set; }
public string Title { get; set; }
public string Slug { get; set; }
public string Content { get; set; }
public string Category { get; set; }
public string Client { get; set; }
public int Year { get; set; }
// more attributes here...
}
I would like to prepare a view model (specific for my view). Here is the view model:
public class ProjectListViewModel
{
public IEnumerable<ProjectInfos> ProjectList { get; set; }
public PagingInfo Paging { get; set; }
public class ProjectInfos
{
public string Title { get; set; }
public string Slug { get; set; }
public string Content { get; set; }
public string Category { get; set; }
public string Client { get; set; }
public int Year { get; set; }
}
public class PagingInfo
{
public int TotalItems { get; set; }
public int ItemsPerPage { get; set; }
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
}
}
In my controller, I would like to prepare the view model by filling it with 2 different objects:
List of projects
Paging information
Here is my controller:
public ViewResult List(string category, int page = 1)
{
IEnumerable<Project> projectList = m_Business.GetProjects(category, page, 10);
PagingInfo pagingInfo = m_Business.GetPagingInfo(category, page, 10);
// Here I need to map !!
ProjectListViewModel viewModel = .....
return View(viewModel);
}
So how can I proceed in my controller? I know we can use automapper to map from one object to another but here I need to map from two objects into a single one.
Thanks.
You can extend AutoMapper to map multiple objects.
Here is a blog which provides some sample cope.
Then you can use code like this:
var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment);
Related
I'm gonna cut to the chase.
I'm creating a Survey platform, it has 3 models.
Model Survey, it has Many SurveyQuestion which has many SurveyAnswer.
(I can insert all of the values of these models but I dont think it is needed)
public class SurveyAnswer
{
[Key]
public int Id { get; set; }
public string Value { get; set; }
public string SubmittedBy { get; set; }
public int SurveyId { get; set; }
public int QuestionId { get; set; }
public virtual Survey Survey { get; set; }
public virtual SurveyQuestion Question { get; set; }
public string Comment { get; set; }
}
Now a problem I'm having is once someone created a survey and another person is starting it, he answers and that's it. How do I show that the next time he comes to an index page? How do I show that "you already submitted this survey"? Do I do that in Controller or in View? I would prefer to that in this action currently (it's a menu for all ongoing surveys).
[HttpGet]
public ActionResult Menu()
{
var survey = Mapper.Map<IEnumerable<Survey>, IEnumerable<SurveyViewModel>>(_unitOfWork.SurveyRepository.Get());
return View(survey.ToList());
}
Put all your validation rules to your AbstractValidator class.
[Validator(typeof(SurveyAnswerValidator))]
public class SurveyAnswer{
[Key]
public int Id { get; set; }
public string Value { get; set; }
public string SubmittedBy { get; set; }
public int SurveyId { get; set; }
public int QuestionId { get; set; }
public virtual Survey Survey { get; set; }
public virtual SurveyQuestion Question { get; set; }
public string Comment { get; set; }
}
public class SurveyAnswerValidator : AbstractValidator<SurveyAnswer>
{
public SurveyAnswerValidator()
{
//list your rules
RuleFor(x => x.SubmittedBy).Must(BeUnique).WithMessage("Already
submitted this survey");
}
private bool BeUnique(string submittedBy)
{
if(_context.SurveyAnswers.
FirstOrDefault(x => x.SubmittedBy == submittedBy) == null){
return true;
}
else{
return false;
}
}
}
If you want to check uniqueness in ViewModel you can use Remote.
public class SurveyAnswerVM{
[Key]
public int Id { get; set; }
public string Value { get; set; }
[Remote("HasSubmitted", "ControllerName")]
public string SubmittedBy { get; set; }
public int SurveyId { get; set; }
public int QuestionId { get; set; }
public virtual Survey Survey { get; set; }
public virtual SurveyQuestion Question { get; set; }
public string Comment { get; set; }
}
Where HasSubmitted is a method you may create in controller to return true if the user has submitted.
RemoteAttribute
https://msdn.microsoft.com/en-us/library/gg508808(VS.98).aspx
The best solution by vahdet (suggested in comments)
[Index("IX_AnswerQuestion", 2, IsUnique = true)]
[StringLength(36)]
public string SubmittedBy { get; set; }
public int SurveyId { get; set; }
[Index("IX_AnswerQuestion", 1, IsUnique = true)]
public int QuestionId { get; set; }
I'm trying to write a View Model in an ASP.NET MVC5 project to show data from different tables on a form that the user can then edit and save. I'm using the following :-
VS 2017, c#, MySQL Database, Entity Framework 6.1.3, MySQL Connector 6.9.9, Code First from Database (existing database that I can't change)
To complicate matters, there are no links between the tables in the database, so I cannot work out how to create a suitable View Model that will then allow me to save the changes.
Here are the 4 table models :-
public partial class evc_bearer
{
[Key]
[Column(Order = 0]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long evcid { get; set; }
[Key]
[Column(Order = 1]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long bearerid { get; set; }
public int vlan { get; set; }
[Column("ref")]
public string _ref { get; set; }
[Required]
public string port { get; set; }
[Required]
public string endpoint { get; set; }
}
public partial class bearer
{
[Key]
public long id { get; set; }
[Column("ref")]
[Required]
public string _ref { get; set; }
public string name { get; set; }
public long? site { get; set; }
public long? provider { get; set; }
public long? mtu { get; set; }
public float? rental { get; set; }
public int? offsiteprovider { get; set; }
public float? offsiteproviderrental { get; set; }
public bool? aend { get; set; }
public int? equipmentport { get; set; }
public string orderref { get; set; }
public string offsiteref { get; set; }
public string notes { get; set; }
public float? bookingfactor { get; set; }
}
public partial class evc
{
[Key]
public long id { get; set; }
[Required]
public string type { get; set; }
public byte servicetype { get; set; }
public byte cos { get; set; }
public int cir { get; set; }
public int pir { get; set; }
public bool burst { get; set; }
[Column("ref")]
public string _ref { get; set; }
public string orderref { get; set; }
public byte state { get; set; }
public string notes { get; set; }
public float? rental { get; set; }
}
public partial class evc_provider
{
[Key]
public long id { get; set; }
[Required]
public string provider { get; set; }
}
This is the View Model I tried writing :-
public partial class evcBearersVM
{
[Key]
[Column(Order = 0)]
public long evcid { get; set; }
[Key]
[Column(Order = 1)]
public long id { get; set; }
[Column("ref")]
public string b_ref { get; set; }
public string b_name { get; set; }
public string ep_provider { get; set; }
public int eb_vlan { get; set; }
public string eb_port { get; set; }
public string eb_endpoint { get; set; }
}
This is the Linq query I used to populate the View Model :-
IQueryable<evcBearersVM> data = from eb in csdb.evc_bearers
join b in csdb.bearers on eb.bearerid equals b.id
join ep in csdb.evc_providers on b.provider equals ep.id
join e in csdb.evcs on eb.evcid equals e.id
where (eb.evcid == evcid && b.id == id)
select new evcBearersVM
{
evcid = eb.evcid,
id = b.id,
b_ref = b._ref,
b_name = b.name,
ep_provider = ep.provider,
eb_vlan = eb.vlan,
eb_port = eb.port,
eb_endpoint = eb._ref
};
So the query works and joins the tables to get the data I need and I can display this date in various views as needed. What I now need to do is be able to edit a row and save it back to the database. I have an Edit View that is showing the data I need but I'm not sure how to save changes given that it's a View Model and the DB Context isn't aware of it. Grateful for any help.
What you should do is, use the same view model as your HttpPost action method parameter and inside the action method, read the entities you want to udpate using the Id's (you can get this from the view model, assuming your form is submitting those) and update only those properties you need to update.
[HttpPost]
public ActionResult Edit(evcBearersVM model)
{
var b = csdb.bearers.FirstOrDefault(a=>a.id==model.id);
if(b!=null)
{
b.name = model.b_name;
b._ref = model.b_ref;
csdb.SaveChanges();
}
// Update the other entity as well.
return RedirectToAction("Index");
}
Relatively new to MVC and can't figure out how to pass data from multiple models into a single view. I know I need to use a view model, but I can't figure out what to do in the controller.
Models:
public class Child
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ChartNumber { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
public string City { get; set; }
public string State { get; set; }
[Display(Name = "Zip Code")]
public int ZipCode { get; set; }
public string Ethnicity { get; set; }
public string Referral { get; set; }
[Display(Name = "Recommended Re-evaluation")]
public bool ReEval { get; set; }
[Display(Name = "Hearing Aid Candidate")]
public bool HaCandidate { get; set; }
[Display(Name = "Fit With Hearing Aid")]
public bool FitHa { get; set; }
public virtual List<ChildEval> ChildEvals { get; set; }
}
public class ChildEval
{
[Key]
public int ChildEvalId { get; set; }
public DateTime Date { get; set; }
public int PtaRight { get; set; }
public int PtaLeft { get; set; }
public int UnaidedSiiRight { get; set; }
public int UnaidedSiiLeft { get; set; }
public int AidedSiiRight { get; set; }
public int AidedSiiLeft { get; set; }
public int ChartNumber { get; set; }
public virtual Child Child { get; set; }
}
}
DbContext
public class UnitedContext : DbContext
{
public UnitedContext() : base("name=UnitedContext")
{
}
public System.Data.Entity.DbSet<United.Models.Child> Children { get; set; }
public System.Data.Entity.DbSet<United.Models.ChildEval> ChildEvals { get; set; }
}
ViewModel:
public class ChildViewModel
{
public class Child
{
public string FirstName { get; set; }
}
public class ChildEval
{
public int PtaRight { get; set; }
}
}
ViewModelController? :
public class ViewModelController : Controller
{
//
// GET: /ViewModel/
public ActionResult Index()
{
return View();
}
}
}
I'm stuck on how to create the controller for the viewmodel and how to actually get the data into the view. Any help would be greatly appreciated!
Don't have a controller called ViewModelController. Controller is the handler between database and the view. Therefore the name of the controller should tell the programmer what kind of data the controller is controlling. By default, it also indicates the subsite you are in your web application ( ViewModelController would yield http://mysite/ViewModel/ ).
Since you are handling children, I'm calling it ChildrenController for now.
Generally a good idea is to wrap your 2 models into one viewmodel and work with that. In this case Model != ViewModel, model is the database model of the entity while ViewModel is the one that's passed to/from the view.
public class Child
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class SomeOtherModel
{
public int ID { get; set; }
public int SomeInteger { get; set; }
public int SomeOtherInteger { get; set; }
}
public class ChildViewModel
{
public Child Child { get; set; }
public SomeOtherModel SomeOtherModel { get; set; }
public ChildViewModel(Child child, SomeOtherModel s)
{
Child = child;
SomeOtherModel = s;
}
}
In your controller
public class ChildrenController : Controller
{
//
// GET: /Children/
public ActionResult Index()
{
Child child = /*Fetch the child from database*/;
SomeOtherModel someOther = = /*Fetch something else from database*/;
ChildViewModel model = new ChildViewModel(child,someOther);
return View(model);
}
}
View:
#model ChildViewModel
#Html.EditorFor(model => model.Child.FirstName)
#Html.EditorFor(model => model.Child.LastName)
First of all, I'm new to MVC.
I want to display the properties of the JSON response in a html view.
For example, i want to get the number of page likes from the JSON response and display just the number of likes on a page.
Any help is much appreciated :)
//
// GET: /Facebook/
public ActionResult Index()
{
var json = new WebClient().DownloadString("https://graph.facebook.com/google");
JsonConvert.DeserializeObject<RootObject>(json);
return view();
}
public class CategoryList
{
public string id { get; set; }
public string name { get; set; }
}
public class Location
{
public string street { get; set; }
public string city { get; set; }
public string state { get; set; }
public string country { get; set; }
public string zip { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
}
public class Cover
{
public string cover_id { get; set; }
public string source { get; set; }
public int offset_y { get; set; }
public int offset_x { get; set; }
}
public class RootObject
{
public string about { get; set; }
public string awards { get; set; }
public string category { get; set; }
public List<CategoryList> category_list { get; set; }
public int checkins { get; set; }
public string company_overview { get; set; }
public string description { get; set; }
public string founded { get; set; }
public bool is_published { get; set; }
public Location location { get; set; }
public string mission { get; set; }
public string phone { get; set; }
public string products { get; set; }
public int talking_about_count { get; set; }
public string username { get; set; }
public string website { get; set; }
public int were_here_count { get; set; }
public string id { get; set; }
public string name { get; set; }
public string link { get; set; }
public int likes { get; set; }
public Cover cover { get; set; }
}
}
}
Your action should pass the object to the view:
public ActionResult Index()
{
var json = new WebClient().DownloadString("https://graph.facebook.com/google");
var root=JsonConvert.DeserializeObject<RootObject>(json);
return view(root);
}
and then in your view you can show whichever property you want:
#Model RootObject
<html>
<head>
<title>Showing properties</title>
</head>
<body>
#Model.likes likes.
</body>
</html>
This is if you use the Razor syntax.
you're missing
return view(root);
You should pass the object back to view to use it.
you can use JsonResult in mvc 4,
public JsonResult ReturnSomeJson()
{
JsonResult result = new JsonResult();
//Assign some json value to result.
//Allow get is used to get the value in view.
return view(result,AllowGet.True);
}
I was looking for a similar solution and I found it to be a bit different:
[HttpGet]
public JsonResult Index() {
// your code
return Json("some result string or value", JsonRequestBehavior.AllowGet);
}
This outputs "some result string or value" in your browser when you call this action directly.
Assuming this is a normal action inside a controller that
inherits from Controller class.
Should T be a for example Customer or CustomerViewModel ?
The annotations bound to Mvc namespace are on the ListViewModel so actually I could pass the Customer object. What do you think?
public class ListViewModel<T>
{
[Required(ErrorMessage="No item selected.")]
public int[] SelectedIds { get; set; }
public IEnumerable<T> DisplayList { get; set; }
}
UPDATE
[HttpGet]
public ActionResult Open()
{
IEnumerable<Testplan> testplans = _testplanDataProvider.GetTestplans();
OpenTestplanListViewModel viewModel = new OpenTestplanListViewModel(testplans);
return PartialView(viewModel);
}
public class OpenTestplanListViewModel
{
public OpenTestplanListViewModel(IEnumerable<Testplan> testplans)
{
var testplanViewModels = testplans.Select(t => new TestplanViewModel
{
Name = string.Format("{0}-{1}-{2}-{3}", t.Release.Name, t.Template.Name, t.CreatedAt, t.CreatedBy),
TestplanId = t.TestplanId,
});
DisplayList = testplanViewModels;
}
[Required(ErrorMessage = "No item selected.")]
public int[] SelectedIds { get; set; }
public string Name { get; set; }
public IEnumerable<TestplanViewModel> DisplayList { get; private set; }
}
public class TestplanViewModel
{
public int TestplanId { get; set; }
public string Name { get; set; }
}
public class Testplan
{
public int TestplanId { get; set; }
public int TemplateId { get; set; }
public int ReleaseId { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedAt { get; set; }
public Template Template { get; set; }
public Release Release { get; set; }
}
T should ideally be a view model. Having a view model referencing domain models is some kind of a hybrid view model, not a real one. But if you think that in this specific case the domain model will be exactly the same as the view model then you could keep it as well.