I have a domain 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; }
}
I have a view model (which is a portion of the above model):
public class ListProjectsViewModel
{
public IEnumerable<ProjectStuff> SomeProjects { get; set; }
public class ProjectStuff
{
public int ProjectID { get; set; }
public string Title { get; set; }
public string Slug { get; set; }
public string Content { get; set; }
}
// Some other stuff will come here
}
I have an action controller:
public ActionResult List()
{
// Get a list of projects of type IEnumerable<Project>
var model = m_ProjectBusiness.GetProjects();
// Prepare a view model from the above domain entity
var viewModel = Mapper.Map..........
return View(viewModel);
}
How can I code the mapping '........' with automapper ?
Thanks.
There are two steps.
1) Define a mapping with AutoMapper (this is usually done in some sort of bootstrapper called by Global.asax, etc.)
// since all of your properties in Project match the names of the properties
// in ProjectStuff you don't have to do anything else here
Mapper.CreateMap<Project, ListProjectsViewModel.ProjectStuff>();
2) Map the object in your controller:
// Get a list of projects of type IEnumerable<Project>
var projects = m_ProjectBusiness.GetProjects();
// Prepare a view model from the above domain entity
var viewModel = new ListProjectsViewModel
{
SomeProjects = Mapper.Map<IEnumerable<Project>, IEnumerable<ListProjectsViewModel.ProjectStuff>>(projects)
};
return View(viewModel);
The thing to note here is that you are defining a mapping between Project and ProjectStuff. What you are trying to map is a list of Projects (IEnumerable) to a list of ProjectStuff (IEnumerable). AutoMapper can do this automatically by putting that in the generic arguments as I did above. Your View Model that your view is using is wrapping your list of ProjectStuff, so I just create a new ListProjectsViewModel and do the mapping inside of that.
Related
I have a model linked to a second table:
public class Rock
{
public int ID { get; set; }
[ForeignKey("Con")]
public int ConID { get; set; }
public virtual Con Con { get; set; }
}
public class Con
{
public int ID { get; set; }
public virtual ICollection<Rock> Rock{ get; set; }
[Required]
[RegularExpression(#"^[0-9A-Za-z '']+$")]
[StringLength(200, MinimumLength = 3)]
public string Name { get; set; }
}
In my control, I have a 'create' action:
// GET: Rock/Create/3337
[Route("Rock/Create/{ConID?}")]
public ActionResult Create(int? ConID)
{
var rock= new Rock();
rock.ConID = (int)ConID;
return View(rock);
}
I'd like to get the con name from that table and send it to the view. At this point it doesn't know the name because there's no 'rock' record linking it yet.
Any suggestions? Thanks in advance!
If you have created a strongly typed view with Rock as Type, you need to either add 'Con Name' property to Rock Type or else you need to create a new Type and add the data to this Type which you want to pass to the View.
public class NewType
{
public int ConID { get; set; }
public string ConName { get; set; }
}
Add the data you want to pass in this Type and return view with this object:-
public ActionResult Create(int? ConID)
{
var newType= new NewType();
newType.ConID = (int)ConID;
newType.ConName = "XYZ";
return View(newType);
}
The two suggestions I would give are to pass Con.name to the view in the viewbag or to create a viewmodel, as Rahul suggested, that combines the properties of different classes that are needed for that particular view.
I use Asp.Net MVC, Entity Framework. I have a form it looks like below.
Here, dropdownlist is filled from a table(types). Checkboxes is filled from another table(test). Tables are like below:
public class Types
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
}
public class Tests
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
}
public class Types_Tests
{
public int Types_TestsID{ get; set; }
public int TypesID { get; set; }
public int TestsID { get; set; }
public virtual Types Types { get; set; }
public virtual Tests Tests { get; set; }
}
Types_test table is relation table between Types and Tests. When I click Kaydet button, it shuld save type and checked tests. I made this operation using ViewBag, javascript and hdnvalue.I added checked checkboz values to a hdntext. I made saving process like below:
[HttpPost]
public ActionResult Index(string drpType, string hdntesttypes)
{
var TypeList = Types.GetAll();
ViewBag.TypesList = new SelectList(TypeList, "Id", "Name");
var testypeList = testTypes.GetAll();
ViewBag.TestTypesList = new SelectList(testypeList, "Id", "TestName");
GenericRepository<TestDisabledTypes> testDisabledRepository = new GenericRepository<TestDisabledTypes>(_context);
if (!string.IsNullOrEmpty(hdntesttypes))
{
string[] disabletypesArray = hdntesttypes.Split(',');
using (TransactionScope trns = new TransactionScope())
{
for (int i = 0; i < disabletypesArray.Length; i++)
{
Test_Types types = new Test_Types ();
types.TestTypesID = Convert.ToInt32(disabletypesArray[i]);
types.TypesID = Convert.ToInt32(drpType);
testDisabledRepository.Insert(types);
}
trns.Complete();
}
}
return View();
}
It wokrs. But I search better solution for this process. Can someone give me any idea?
Thanks.
If you don't need additional attributes for your entity class, you don't need create link table.
Just define the following class, and EF will generate the link table for you automatically.
public class Type
{
public int TypesID{get;set;}
public string TestName { get; set; }
public string TestExplanation { get; set; }
public int TestTime { get; set; }
public ICollection<Test> Tests { get; set; }
}
public class Test
{
public int TestID{get;set;
public string Name { get; set; }
public string Code { get; set; }
public ICollection<Type> Types {get;set;}
}
Well, in EntityFramework if you want to create a many to many relation object you need to create new object of "linking" entity. Unfortunately, it is not possible to add first object, add second object and say "Guys, you are in many to many relationships. Are you happy then?" :) You need to create relation object, set appropriate fields in it (I think these are ids of two objects itself) and add it to relation collection (entity) in your model. But before doing so you need to be sure that objects with data you are linking with are already exists in database. Otherwise you'll get an error
Also it's not necessary to create manually transaction because EF does it for you automatically each time you get/save your data
Can someone explain to me how to use multiple models with a single view in which each of the models represent a DB table?
What I've currently done is created a model file for each model.
Example Model:
[Table("Order")]
public class OrderModel
{
[Key, Column(Order = 0)]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int OrderID { get; set; }
[Key, Column(Order = 1)]
public int UserID { get; set; }
public UserProfile Account { get; set; }
public DateTime Date { get; set; }
public int ShipLocation { get; set; }
public string PONumber { get; set; }
public int StatusID { get; set; }
public StatusModel Status { get; set; }
}
Here is the other model that encompases all the models to use in a single controller / view.
public class OrderPlacementModel
{
public OrderModel OrderChild { get; set; }
public OrderItemsModel OrderItemsChild { get; set; }
public StatusModel StatusChild { get; set; }
public MaterialsModel MaterialsChild { get; set; }
public CategoryModel CategoryChild { get; set; }
public PackModel PackChild { get; set; }
}
public ActionResult PlaceOrder()
{
var viewModel = new OrderPlacementModel
{
OrderChild = new OrderModel(),//or fetch this object from your data source
OrderItemsChild = new OrderItemsChild(),
//...etcetera
};
return View(viewModel);
}
Edit
Or, if you've strongly typed your view to a List<OrderPlacementModel> instead of a single instance, you could do something similar to this:
public ActionResult PlaceOrder()
{
var viewModel = new List<OrderPlacementModel>();
var model = new OrderPlacementModel
{
OrderChild = new OrderModel(),//or fetch this object from your data source
OrderItemsChild = new OrderItemsChild(),
//...etcetera
};
viewModel.Add(model);
//lather, rinse, repeat for however many instances you need to send to your view.
return View(viewModel);
}
Ideally, you should create a view model for the view that encompasses the fields from each model that you need to expose via the view. You can then map these in your controller. I would keep your mapping classes completely ignorant of your view models. Keep your views independent of your data model.
public class OrderViewModel
{
public int OrderId { get; set; }
public int UserId { get; set; }
public DateTime Date { get; set; }
public int ShippingLocation { get; set; }
public List<ItemViewModel> Items { get; set; }
}
public class ItemViewModel
{
public int ItemId { get; set; }
public int Title { get; set; }
}
Note how I have created a view model for the order and - to allow the order have multiple items - have separated these out into a separate model class. Now, you can type your view to OrderViewModel and use as many instances of ItemViewModel as your require.
You can then map your viewmodels to database entities from your controller:
[HttpPost]
public ActionResult ConfirmOrder (OrderViewModel model)
{
if (ModelState.IsValid)
{
foreach (ItemViewModel item in model.Items)
{
/* Create instance of OrderItemsModel (or whatever your
DB mapping class is), populate with appropriate data
from 'item' and commit to database. */
}
OrderModel order = new OrderModel();
order.OrderId = model.OrderId;
order.UserId = model.UserId;
order.Date = model.Date;
order.ShipLocation = model.ShippingLocation;
/* TODO: Commit new order to database */
}
}
Doing things this way adds a little overhead to your initial development time but allows you a great deal more flexibility as you aren't forced to mould all of your views to the shape of your entity classes.
I'm using ASP.NET MVC4 EF CodeFirst.
Need help to write LINQ (to entities) code in Index action to get collection of Courses which are attended by selected student. The relationship is many to many with join table with payload.
//StudentController
//-----------------------
public ActionResult Index(int? id)
{
var viewModel = new StudentIndexViewModel();
viewModel.Students = db.Students;
if (id != null)
{
ViewBag.StudentId = id.Value;
// *************PROBLEM IN LINE DOWN. HOW TO MAKE COURSES COLLECTION?
viewModel.Courses = db.Courses
.Include(i => i.StudentsToCourses.Where(t => t.ObjStudent.FkStudentId == id.Value));
}
return View(viewModel);
}
The error I got is:
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
I have modeles (the third one is for join table with payload):
//MODEL CLASSES
//-------------
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public virtual ICollection<StudentToCourse> StudentsToCourses { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string Title { get; set; }
public virtual ICollection<StudentToCourse> StudentsToCourses { get; set; }
}
public class StudentToCourse
{
public int StudentToCourseId { get; set; }
public int FkStudentId { get; set; }
public int FkCourseId { get; set; }
public string Classroom { get; set; }
public virtual Student ObjStudent { get; set; }
public virtual Course ObjCourse { get; set; }
}
Then, here is modelview I need to pass to view
//VIEWMODEL CLASS
//---------------
public class StudentIndexViewModel
{
public IEnumerable<Student> Students { get; set; }
public IEnumerable<Course> Courses { get; set; }
public IEnumerable<StudentToCourse> StudentsToCourses { get; set; }
}
EF does not support conditional include's. You'll need to include all or nothing (ie no Whereinside the Include)
If you need to get the data for just certain relations, you can select it into an anonymous type, something like (the obviously untested);
var intermediary = (from course in db.Courses
from stc in course.StudentsToCourses
where stc.ObjStudent.FkStudentId == id.Value
select new {item, stc}).AsEnumerable();
Obviously, this will require some code changes, since it's no longer a straight forward Course with a StudentsToCourses collection.
In the MVC 3 i want to display data from two models viz. Student and Enrollment into a single view.
Student model
public class Student
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int student_id { get; set; }
public string student_name { get; set; }
public string father { get; set; }
}
Enrollment model
public class Enrollment
{
[Key]
public int enrollment_id { get; set; }
public string rollno { get; set; }
public int student_id { get; set; }
public string registration_no { get; set; }
public date registration_date { get; set; }
}
My ViewModel looks like this
public class StudentEnrollmentViewModel
{
public Student_Info Student_Info { get; set; }
public Enrollment_Info Enrollment_Info { get; set; }
[Key]
public int ID { get; set; }
}
How do I retrieve the data from the two model and assign it to a viewmodel so that I can display it in a view? I am using Repository Design Pattern.
Generally speaking, a controller would be responsible for contacting the model, storing the result set returned in a variable/array/struc that the view would consume. The model and view components/classes would be registered in the controller.
An example:
<event-handler event="display.institutions" access="public">
<notify listener="userInstitutionRights" method="getInstitutionsWithDataRightsNOXML" resultKey="request.institutions" />
<view-page name="userNav" contentKey="request.userNav"/>
<view-page name="userInstitutions" contentKey="request.pageContent"/>
<announce event="assemblePage" />
</event-handler>
Event display.institutions is calling a model component userInstitutionRights and storing the result in a resultKey request.institutions and is including two view pages userNav, userInstitutions where the resultKey is available to each.
You can use DynamicPage, Look into following example
We need to use a Dynamic view page. (More Information)
Follow following steps:
Create DynamicViewPage type
public class DynamicViewPage : ViewPage
{
public new dynamic Model { get; private set; }
protected override void SetViewData(ViewDataDictionary viewData)
{
base.SetViewData(viewData);
Model = ViewData.Model;
}`
}
Your Controller will look like
public ActionResult Account(string returnUrl)
{
LoginModel loginmodel = null;//Initialize Model;
RegistrationModel registrationModel = null ;//Initialize Model;
// Any Extra logic
return View("Account", new
{
Login = loginmodel,
Register = registrationModel
});
}
your View should Inherit from
Inherits="DynamicViewPage"
Now #Model.Login will give you Loginmodel
#Model.Register will give you RegisterModel
It should work as you expected.........