Not sure how to explain this, but here goes...
I've built a code first data model using EF 4.3. One of classes, "Address" contains typical address data, street, city, state, etc. Other classes in the model contain instances of the "Address" class.
The problem. The data will be gathered/presented using different views, some of which will require the address fields, others that will not.
I can build different view models, each having the necessary validation attributes, and copy the data back and forth between data model and view model but that seems wrong.
What am I missing? There has to be a smarter way to do this.
Thanks for your help,
Jimmy
First read these questions and their answers:
MVC: Data Models and View Models
Why Two Classes, View Model and Domain Model?
also this article could help:
ASP.NET MVC View Model Patterns
In conclusion, I think in most scenarios it's helpful to have a chubby domain model (DM) but light weight presentation models (PM) related to it. So when we want to edit only a small chunk of that fat DM, one of our PMs will raise its hand.
Imagine this class in DM:
namespace DomainModels
{
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime? DoB { get; set; }
public MyAddressDM Address { get; set; }
public string Phone { get; set; }
public IEnumerable<MyCarModel> Cars { get; set; }
//etc.
}
}
Now imagine that in one view we need to edit only Address and Phone. A light weight PM could be like:
namesapce PresentationModels
{
public PersonAddressPhone
{
public int ID { get; set;}
public string FullName { get; set;}
public string AddressSteet { get; set; }
public string AddressCity { get; set; }
public string AddressState { get; set; }
public string AddressZipCode { get; set; }
public string Phone { get; set; }
}
}
and in another view we need to add/remove cars for a person:
namesapce PresentationModels
{
public PersonCars
{
public int ID { get; set;}
public string FullName { get; set;}
public IEnumerable<PMCar> Cars { get; set;}
}
}
Mapping between DO and PM is the golden piece of this puzzle. Be sure to take a look at AutoMapper.
Related
I've been following the contoso university tutorial on Microsoft´s site and I have some doubts about how the Entity Framework is doing some stuff. Here we go...
On the beginning of the tutorial, we created three classes that will be turned into tables in my database.
I´d like to know when and how entity instantiates my classes to populate the objects.
Im using code-first approach.
Example:
The classes im using:
public class Course
{
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public decimal? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
public class Student
{
public int StudentID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
After following the tutorial I can now list all my Students and theirs respectives Course(s), as well as their properties in enrollments lists.
When did entity instantiated my Student classes and populated it with the respective Enrollment(s) lists?
How does it know what enrollments are linked to that student?
I dont see any new constructor() ever beeing called.
This might be simple but Im kinda lost here.
Thanks
It doesn't instantiate anything ahead of time, and it doesn't have to. And there won't be anything in the table representing the virtual property as such, either.
These virtual properties are used by EF at runtime to store navigation information, and the collections can be null or contain 0 or more elements. There's no magic, it's just by design that EF "new"s up the collection when it needs to.
If you want to be explicit about it, you can create a constructor on your POCO as well and set your collection equal to a new hashtable.
I'm trying to find out how I can re-use a simple 'Comment' entity type for multiple scenarios where something is 'commentable' in my application.
At the moment, I have a couple of entities that a user is able to post comments to. Examples include Blogs, Profiles and Photos - these can all be 'commented' on.
I'd like to be able to use the same 'Comment' class for each of these scenarios, but I don't want to end up with one HUGE table full of comments for everything. I figure it would be much more efficient to at least store a table of BlogComments, PhotoComments, and ProfileComments. At the moment, my Comment class looks like this:
public class Comment
{
[Key]
public int Id { get; set; }
public int ContextId { get; set; }
[StringLength(256)]
public string Content { get; set; }
public DateTime DatePosted { get; set; }
public virtual Member Author { get; set; }
}
Presumably, I'd need the 'ContextId' field to refer to the particular thing being commented on. This Id might be the Id of a Blog, a Profile or a Photo. I was hoping to be able to refer to comments much like a normal ICollection in these classes, and I have some code like this for the Photos as an example:
public class Photo
{
[Key]
public int Id { get; set; }
[StringLength(48)]
public string FileName { get; set; }
public virtual Member Owner { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
I've been pointed to various articles during my searches, but none really seem relevant to my particular situation. How can I map these comment collections to different tables, and avoid having a comment "super-table"?
Any help, pointers or advice would be hugely appreciated :)
You can create an abstract Comment class and inherit from it specific comments such as PhotoComment, ProfileComment. You will be able to map the comments to different tables.
public abstract class Comment
{
[Key]
public int Id { get; set; }
[StringLength(256)]
public string Content { get; set; }
public DateTime DatePosted { get; set; }
public virtual Member Author { get; set; }
}
public class PhotoComment : Comment
{
public int PhotoId { get; set; }
public virtual Photo Photo { get; set; }
}
public class Photo
{
[Key]
public int Id { get; set; }
[StringLength(48)]
public string FileName { get; set; }
public virtual Member Owner { get; set; }
public virtual ICollection<PhotoComment> Comments { get; set; }
}
I'm trying to create some complex form scheme in a .NET MVC 3 project (or so I think). I'll show a wireframe so that you can understand better.
As you can see from the pic above, it's a form to create a new Car Dealership. I can choose from many available car's manufacturers (in the Add a tab), and each selection creates a new tab in the panel underneath it. In each panel there's a html fieldset, and I can add some new cars on it.
In the end, I want to submit all the form, which comprehends the data from the dealership (e.g. name), the car's brands that it has and the cars available for each brand. How can I do it with MVC 3? I don't know how exactly should I instantiate the model Car Dealership and its respective View. What should the cars in the panels be? An array of inputs? And how can I separate the inputs from one tab from the ones of another? All of this, using Razor!
My real-world scenario is a little bit more complicated, but I'll start by this so that I can try to solve the rest by myself. I'm using jQuery/jQuery UI, but I'm opened to other javascript alternatives (like Backbone, etc - I just don't know them yet). Thanks in advance!
UPDATE (1):
These are my models so far:
public class CarDealership
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ManufactorOnDealership> ManufactorsOnDealership { get; set; }
}
public class Manufactor
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ManufactorOnDealership> DealershipsOfManufactor { get; set; }
}
// Junction class: I believe it's needed because the list of Cars belongs to this relationship
public class ManufactorOnDealership
{
public int Id { get; set; }
public int CarDealershipId { get; set; }
public int ManufactorId { get; set; }
public virtual CarDealership CarDealership { get; set; }
public virtual Manufactor Manufactor { get; set; }
public virtual ICollection<Car> CarsOnDealership { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ManufactorOnDealership> Manufactors { get; set; }
}
This is a question about Models, ASP.NET MVC 3 and relationships. I'm using the code-first approach.
Imagine this simple typical scenario of an User with its Blog Posts:
public class User
{
public virtual int UserId { get; set; }
public virtual string Nickname { get; set; }
public virtual List<Post> Posts { get; set; }
}
public class Post
{
public virtual int PostId { get; set; }
public virtual string BlogText { get; set; }
}
I made it very very simple.
Well. When I create a controller using the Controller with Read/Write actions and views using Entity Framework, the collection of Posts is not considered. It's being ignored. So, I can't get this relationship to work.
If, in place of the collection, there was a single object (public virtual string Email, for example) it works normally.
I'm asking myself and to you:
Why
How do I put references to collections in my model?
It should be a simple task, I really can't understand why it doesn't work.
Thank you.
POCO should look like below to have one-to-many relationship:
public class Post
{
public int Id { get; set; }
public string BlogText { get; set; }
public virtual User User { get; set; }
}
public class User
{
public int Id { get; set; }
public string Nickname { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
I'm having trouble passing view information from my Get/Create action to my view. Here are my three model classes;
public class Competition
{
public int Id { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Prize { get; set; }
}
public class CompetitionEntry
{
public int Id { get; set; }
public int CompetitionEntryId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int CompetitionId { get; set; }
}
public class CompetitionEntryViewModel
{
public int Id { get; set; }
public Competition Competitions { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Here is my Get/Create action in CompetitionEntry Controller;
public ActionResult Create(int id)
{
CompetitionEntryViewModel competitionentryviewmodel = db.CompetitionEntriesView.Find(id);
return View(competitionentryviewmodel);
}
I know this doesn't work. The id parameter goes into the URL fine. How to I get access to my Competition class in th Get action? I need to be able to show the competion name on my Create Competition entry view.
Thanks in advance!
public ActionResult Create(int id)
{
var data = db.CompetitionEntriesView.Find(id);
CompetitionEntryViewModel competitionentryviewmodel = new CompetitionEntryViewModel();
competitionentryviewmodel.CompetitionName = data.Name;
return View(competitionentryviewmodel);
}
What you are trying to do is build an object graph and display it through a view model. In order to do this, you need to map your domain model(s) to your view model.
You can do the mapping yourself by writing a lot of code (re-inventing the wheel), or, you could consider using third party tools to do this for you. I recommend you use an AutoMapper as it is very simple to use imo.
The other problem is that your view model contains a domain model. This is likely to cause you a lot of headache in near future. If I were you, I would replace Competition with CompetitionViewModel.
I would also consider creating a view model for a list of competitions, i.e. CompetitionsViewModel. Look into partial views to see how you can display a list of competitions.
Good luck