I believe this is an AutoMapper basics question:
I have an single "article" Entity Framework entity that I am mapping to a viewmodel to pass to a view for edits. This works fine:
Mapper.CreateMap<Article, ArticleAdmin>();
var articleData = Mapper.Map<Article, ArticleAdmin>(articleEntity);
Now, my EF model includes many-to-many relation to a Topics table via a TopicArticles lookup table, and I want to manage associations when I'm editting the article data.
So I add this to my viewmodel:
public ICollection<TopicArticle> TopicArticles { get; set; }
I believe this is correct specification to mirror the entity type -- my EF model has the TopicArticles association member as an EntityCollection.
and I add a second viewmodel class to populate the list:
public class TopicArticle
{
public int ArticleId { get; set; }
public int TopicId { get; set; }
public bool IsPrimaryTopic { get; set; }
}
When I run the mapping, I get "Missing type map configuration or unsupported mapping." Which is understandable as I've not told Automapper about my TopicArticle viewmodel class.
So:
QUESTION:
How do I change my mapping to account for this extra layer?
(I don't really understand the Automapper syntax for how this should be mapped.)
Also: have I missed anything else?
NOTE / UPDATE:
There were some errors in my posted code, any "publication" that appeared was incorrect, and should have been "article" -- that was because I'm simplifying the situration a bit: articles actually inhereit from publications, but I did not want that complexity in this Question.
OK, this really is basic. My problem was not getting to the actual Automapper documentation. Googling "automapper documentation" gets this link as the top response:
http://automapper.codeplex.com/documentation
which is a useless TOC.
The real documentation is accessed from the home page.
The answer to my question is simple:
First, I change the name of my second viewmodel class for clarity:
public class TopicArticleAdmin
Then back in my action, I add one more mapping line:
Mapper.CreateMap<Publication, ArticleAdmin>();
Mapper.CreateMap<TopicPublication, TopicPublicationAdmin>();
var articles = Mapper.Map<IEnumerable<Publication>, IEnumerable<ArticleAdmin>>(
articleEntities
);
Related
In MVC theory, the Model is the business domain class. For instance, we can have a Person class:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
In ASP.NET MVC, a ViewModel class is often used. This class can be tailored to suit a specific View:
public class PersonViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Deactivate { get; set; }
}
In this example, FirstName and LastName will be combined in one string (Name), and there will also be a "Deactivate" checkbox on the form which will cause deactivation of the person.
In Controller, we populate the PersonViewModel object from the Person object. But, on the very first line of the View, we declare that the Model for this View is PersonViewModel.
#model PersonViewModel
Isn't the Model actually the class that is bound to the View (at least as far as ASP.NET MVC is concerned)?
If my Model is actually the PersonViewModel class, can I call this class just PersonModel? Or is this wrong and misleading?
In my opinion, this is easier to write (and read), and it would also be easier to explain to developers just starting with ASP.NET MVC. Isn't it better to leave out the ViewModel term completely, which can be confused with the ViewModel in the MVVM pattern?
Of course there is no absolute answer to this question,
What the convention "says" is that "PersonViewModel" is a class that is based on "Person" class, but is to be used in an MVC View.
Even in the basic MVC projects you have LoginViewModel etc... so it is also should be understandable for new mvc developers.
For just using PersonModel, is confusing because "Person" is already a Model, so why naming a class PersonModel? doesn't make sense.
If you want to shorten it, you should use PersonView. (but again, the convention is PersonViewModel)
I think that there is no good answer for this question. Both of the names you provided are self explanatory and could be used.
As Robert C. Martin writes in his books in such situation the most important thing is consistency and standardization. If you work in team of few developers you should use common approach to such problem and always use same code pattern to avoid confusion. Because such confusion is a waste of developers time.
I would recommend you this Clean Code: A Handbook of Agile Software Craftsmanship brilliant book about clean code where you can find answers and suggestions for many problems like this one.
In my current team we would use such convention:
PersonDom - person data object model
Person - person view model
for ( int i = 0; i < libraryList.Count; i++)
{
if (ModelState.IsValid)
{
context.Library.Add(libraryList[i]);
context.SaveChanges();
}
}
A library contains an entity 'predefinedgoals' which is already set up in the DB. So when the above code runs it stores dublicates of 'predefinedgoals' and assigns new ID's to them.
I read that I should attach the existing entity to the context but I'm not sure how to to do it in my scenario. The classes look like this:
class library
int libraryID
list<book> bks
.
class book
int bookID
list<importantdates> impdts
.
class importantdate
int importantdateID
predefinedgoal predfg
int numberofresellers
.
class predefinedgoal
int predefinedgoalID
string description
int daysfrompublication
I tried something like this right after ModelState.IsValid but I sense I'm doing it wrong:
var prdfgs= context.predefinedgoals.ToList();
foreach(var pg in prdfgs)
context.predefinedgoals.Attach(pg);
This answer is going to be based on a couple of assumptions, but I've seen this exact problem so many times that this is automatically my go-to answer.
What I think you're doing is that you're creating Library, Book, and ImportantDate objects (and setting up all of the relationships between them as well). In the process of doing all of this, however, you are trying to set the PreDefinedGoal navigational property on those ImportantDate objects, all the while leaving the actual int FK property (that would be something like PreDefinedGoalID), still set to 0. When that happens, Entity Framework disregards the fact that the object contained in the navigational property has an ID on it, and assumes that you are trying to create this PreDefinedGoal object from scratch, just like you're creating the ImportantDate object (as well as the others). It will then create a PreDefinedGoal object with the exact same data as the one you're actually trying to use, but it will create it as a separate, duplicate record in the database.
The solution to your problem then is simple: Don't set the navigational property. Just simply set the FK (ImportantDate.PreDefinedGoalID) to the ID of the PreDefinedGoal object that you want to hook up to it. When you do that, and you save it, Entity Framework will then reach out to the database for the correct object based on that ID, and thus you will avoid having duplicate PreDefinedGoal objects in your database.
FYI: I learned this from one of Julie Lerman's MSDN posts. If you're going to be working with EF, I highly recommend reading her posts and columns.
I am in the same situation and found a workaround. The way this workaround works makes me think that in this case EF is to blame for handling the situation badly.
In order to simplify the example I will just post an example with one object and it's navigational property.
public class Topic
{
int Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
}
public class Course
{
int Id { get; set; }
public Topic Topic { get; set; }
// additional properties don't matter now
}
Note the absence of any foreign key or other data annotations. EF6 will correctly create the database schema from this and infer that Id is the primary key.
Without workaround adding a new course for an existing topic will create a new topic object with a new Id (overwriting the Id it was given!) :
db.Courses.Add(course);
await db.SaveChangesAsync();
The braindead workaround:
course.topic = db.Topics.Find(course.topic.Id);
db.Courses.Add(course);
await db.SaveChangesAsync();
In other words, if the topic has been loaded from the context directly, EF will recognize it as an existing topic and don't try to add it again.
Update: To just attach the entity without reloading it:
db.Topics.Attach(course.topic);
However you will run into more issues with this setup, it is probably best to use ForeignKey attribute(s) and include the TopicId in Course object. Following works OK but still looks ridiculous to me:
[ForeignKey("Topic")]
public int TopicId { get; set; }
[ForeignKey("TopicId")]
public virtual Topic Topic { get; set; }
Would love to hear about a less redundant solution though.
The answer to why it stored duplicates in my scenario was that I performed tasks in two different classes - using different database context variables in each of them.
So class #1 is the one in my question, that's where I'm saving to the DB using context #1. In class #2 I retrieved all the PredefinedGoals and added them to ImportantDates but to do this I created context #2. The ID's and objects were the same but retrieved from different context variables.
I solved it by retrieving the PredefinedGoals in class #1 with context variable #1 and sent them as an argument to class #2.
I am building an ASP.Net MVC application using a ViewModel approach to keep my domain entities separate from the "models" used by my UI. I am using the following convention for naming my ViewModel classes. ViewModelName = ViewName + "ViewModel". For example:
Index + ViewModel = IndexViewModel
So far, so good, this is a fairly common pattern and there is a lot of guidance on this topic on StackOverflow and elsewhere. My question concerns child objects used by my ViewModels. If my ViewModel requires a class with properties identical to my a domain model object, I simply include the domain model within my ViewModel. For example:
public class PersonViewModel
{
public int PersonID { get; set; }
public Address Address { get; set; }
public string SomeOtherProperty { get; set; }
}
However, I am not sure what naming convention to use when I need a child object with different properties from my domain model. For example if Address needed a few additional properties besides what is in the Address domain model, what should I call it? I considered AddressViewModel like so:
public class PersonViewModel
{
public int PersonID { get; set; }
public AddressViewModel Address { get; set; }
public string SomeOtherProperty { get; set; }
}
but that just doesn't feel right to me. My gut instinct is that the ViewModel suffix should only be for the top level ViewModel.
I am looking for suggestions from other developers on what naming conventions they use in this scenario, specifically what would you call the child object in this case?
I'm going to put an answer on this just because no one else has! (I know I'm a little late to this party!)
I've pondered over this exact thing many times and tried different conventions over the years. The one thing I picked up on is that you are using a naming convention...
If your naming convention is to suffix your UI model classes with 'ViewModel' then the child models should have the same suffix otherwise you're breaking your own convention!
Also lets say you have an Address table (or whatever you have) and a Customer can have an address and a Company has an address and they both use the same table, then you may use the same child model for both parent models. It seems right to have an AddressViewModel. One day you might have a View/PartialView and it's model is IEnumerable<AddressViewModel>
I know there's no real right answer to this, but this is my answer :-)
I read this q/a Real example of TryUpdateModel, ASP .NET MVC 3 and was really interested on #ben-foster response.
I started doing a comment on that answer but got quite long, so started a new Question.
Having ViewModels for everything approach (which i like a lot) get me into some 'weird scenarios' that i want advice in how should I do.
Imagine this structure :
public class ProductListEditableViewModel {
List<ProductEditViewModel> products {get;set;}
}
public class ProductEditViewModel {
List<PriceViewModel> prices {get;set;}
}
public class PriceViewModel {
CurrencyViewModel currency {get;set;}
}
and so on ... ? do you really make one view model for each inner class? how then you map all that to the Model Object?
Also, that covers the Edit, but I have an Add, a send via email, and potentially more Views so more ViewModels!! should i end like something :
AddCurrencyViewModel
QuickAddCurrencyViewModel
EditCurrencyViewModel
ListCurrencyViewModel
DeleteCurrencyViewModel
ShareCurrencyViewModel
all having the 'almost same' properties ?
Should all those be packed into one file ?
Also do i need all this all viewModels or a inheritance approach might be better?
If you can, I´ll appreciate elaborate on complex scenarios
Also, I use a DTO approach to expose some of the model objects into web service / apis, so I already have some form of mapping already in place where this DTO are not exactly my ViewModels, should I remove one of them? what´s the suggestion in this scenario ?
I´m using entity framework but i think the question is (or should be) ORM agnostic.
Not using UoW pattern (will this helps?) as looks it´s gets more complicated as the depth of the object increases.
Thanks a lot!
We typically have a view model per view so yes, if you have lots of views you will have lots of view models.
In typical CRUD applications we often have very similar views, for example Add and Update. In these cases, yes we use inheritance rather than writing duplicate code - usually Add subclasses Update.
public class AddFoo : UpdateFoo {
public AddFoo() {
// set up defaults for new Foo
}
}
public class UpdateFoo {
public string Name { get; set; }
// etc.
}
We attempted to "share" view models between views in the past and normally ended up in a world of pain.
With regard to your "weird scenario" - this does look weird indeed, but perhaps because I don't understand your application.
The goal of your view model is to provide the information to the view that is needed and ideally to flatten any complex objects so they are easier to work with. You shouldn't split your view models up like your example unless it makes sense to do so.
Let's say I wanted to a create a view where the customer could change their contact details. Taking the following domain object:
public class Customer {
public string FirstName { get; set; }
public string LastName { get;set; }
public Address Address { get; set; }
}
I'd probably flatten this to a view model like so:
public class UpdateAddressModel {
public string FirstName { get; set; }
public string LastName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressCity { get; set; }
// etc.
}
Of course there will be occasions where it doesn't make sense to do this, for example a dashboard view in an online store where you have a list of products going out of stock and a list of recent orders - these two things are unrelated but are required by your view:
public class DashboardModel {
public List<Product> ProductsGoingOutOfStock { get; set; }
public List<Order> NewOrders { get; set; }
}
how then you map all that to the Model Object?
I'm assuming by Model Object you mean your data/domain model. The key takeaway here is that the view model you use to render your view is unlikely to be the same as the "models" you POST to the server and if they are, you're probably over-POSTing or you have some crazy enter-everything data capture screen that will make your eyes bleed.
I find it helps to think of what you send to your server as Commands and what you use to render your views as view models.
So the answer to your question - how do you map your complex view model to your data model? - Quite simply, you don't. You should send commands to the server that perform a specific task e.g. updating an address.
There's no hard and fast rule in how you structure your view models but generally go with what makes sense and if it starts to feel too complicated you're probably trying to do too much with one view.
I hope this helps. You'll find lots of posts relating to this matter on my blog.
I realize this is an old-ish question but I did want to address one of the questions posed by the OP that was not answered.
Should all those [ViewModels] be packed into one file ?
Most of the examples I see put each ViewModel in a separate file, so the dominant convention seems to be one file per viewmodel, but I found in practice that this seems to be overkill. Instead I put all viewmodels for a particular controller in one file with multiple viewmodels in it. So for example if User is my Controller and I have several viewmodels associated with this controller such as UserAddViewModel, UserEditViewModel, UserDeleteViewModel I put all of the viewmodels for User in one file called UserViewModels.cs
So I am new to MVC and am working now with MVC3 and the Entity Framework. I am currently using a Model/Schema 1st approach as the database already exists. Therefore I create my ADO.NET Entity Data Model (.edmx) and I have all the needed entities in my MVC app. So far so good on all this.
However let's say one of my Entities is a 'Customer' entity. I can see the auto-generated partial class inheriting from EntityObject in MyEntites.Designer.cs. At this point I want to add some custom business logic to my MVC Model. Natuarally I believe the answer is to use my own partial class created in the Model named 'Customer' as well.
I did a lot of searching on this before asking the question and see all kinds of information on POCO, T4 templates, modifying auto-generated code, etc and am lost. Is it a royal pain to add my own business logic and custom code to the auto-generated entities from EF? I certainly don't want to modify the auto generated code over and over.
I need a straight forward explanation to make the proverbial 'light bulb' go on, and then I can take-off from there. Can someone help me answer how to do this please?
Thanks!
Keep your own class code in a different file, but use the same class and namespace. This will help avoid your code being overwritten by the T4 code generator.
Extending Entity Framework Generated Types
You can also add attributes to generated classes by using a meta class:
Adding Attributes to Generated Classes
Those codes are auto-generated and will be over written on each model update or change.
You can achieve what you need through extending models. Suppose that EF generated the following entity class for you:
namespace YourSolution
{
using System;
using System.Collections.Generic;
public partial class News
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int UserID { get; set; }
public virtual UserProfile User{ get; set; }
}
}
and you want do some work arounds to preserve your you data annotations and attributes. So, follow these steps:
First, add two classes some where (wherever you want, but it's better to be in Models) like the following:
namespace YourSolution
{
[MetadataType(typeof(NewsAttribs))]
public partial class News
{
// leave it empty.
}
public class NewsAttribs
{
// Your attribs will come here.
}
}
then add what properties and attributes you want to the second class - NewsAttribs here. :
public class NewsAttrib
{
[Display(Name = "News title")]
[Required(ErrorMessage = "Please enter the news title.")]
public string Title { get; set; }
// and other properties you want...
}
Notes:
1) The namespace of the generated entity class and your classes must be the same - here YourSolution.
2) your first class must be partial and its name must be the same as EF generated class.
Go through this and your attribs never been lost again ...