I am in the process converting a large classic ASP web application to ASP.Net MVC with domain driven design. While much of my domain fits well with DDD, I keep running into situations where a pure DDD approach is not appropriate. For example the read side of my application varies significantly from the write side. No problem, I created a separate read model, and implemented a simplified version of CQRS (no event sourcing, no separate db). Another issue was bulk database operations. No problem, that is being implemented as a service. Here's my current quandary. Our system allows users to make changes to the system that are effective on some future date. To accommodate this we have a database table that stores the pending changes until the effective date. On the effective date, an automated task runs and performs the actual database updates. The update task can include domain logic, so that part fits with DDD and is not a problem. To help visualize what is going on, here is the class that handles the pending update:
public class PendingChanges
{
public int EntityID {get; set;}
public string FromTable {get; set;}
public string DetailField {get; set;}
public string NewValue {get; set;}
public DateTime EffectiveDate {get; set;}
public DateTime EnteredDate {get; set;}
public int UserID {get; set;}
public string UserName {get; set;}
public string UserArea { get; set; }
// Business logic and validation here?
}
As you can see this is a generic class that can handle updates to various database tables. It basically stores the database column that is being updated, the new value that the column will be, the table that it belongs in, the effective date and some logging data.
So here are my questions: Should the logic that collects the pending update and stores it in the pending updates table be modeled as a domain object or should it be handled some other way, for example as a service?
To put it another way is PendingChanges itself a domain entity with its own domain logic? There are some business rules that apply to PendingChanges as distinct from the entities that the changes are taking place on. For example what constitutes a UserArea could be considered a business rule as would be legal values for FromTable, not to mention validation.
Or is PendingChanges a value object since it is reusable across different domain objects? If that is the case does it make more sense to use PendingUpdatesService?
Is part of the Domain the concept of doing db updates i.e are you building database management/reporting software? If PendingChanges has a meaning for your Domain then maybe is an entity, although this technicality matters less, getting the proper domain modelling is much more important. If PendingChanges is a class that your app is using to update (domain)things in the db, then it has nothing to do with DDD nor with your domain. It is a part of your infrastructure. Good OOP is still needed though, but no DDD buzzwords here.
Btw, if an object has an id, it usually is an Entity.
Related
I just learn that with the [Contained] attribute I can define a contained collection. This means the collection is no more accessible from my root oData system. Ok fine, but here is my model:
I have a user that have addresses
The user has invoices
Each invoice can have one or two addresses from the user.
On which collection should I add the contained attribute?
The answer to this completely depends on your domain model. The advice I would give is to use OData containment sparingly. It really only makes sense to use it if the entity you are marking as being a contained entity cannot exist outside of the context of the parent entity. Because of this constraint I think the use cases for OData containment are few and far in between. The advantage over a separate controller is that it can make more sense from an architectural standpoint. However your controllers become more bloated and it is more work to maintain the ODataRouteAttributes on your methods. Something which is not necessary when using convention based routing.
The example on the guide to set up OData containment explains it somewhat. It falls a bit short on why you would use it. Note that the PaymentInstrument entity has no foreign key to Account. This means that there is no separate table where the PaymentInstrument information is stored. Instead it is stored directly on the Account record. Yet is still defined as a Collection<T> so it is probably stored as JSON or across multiple columns. This might not necessarily be the case, but from a code standpoint the database could look like that.
To further explain OData containment let's say we have the domain model below.
public class HttpRequest
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public virtual HttpResponse HttpResponse { get; set; }
}
public class HttpResponse
{
public string Content { get; set; }
public DateTime CreatedOn { get; set; }
}
As you can see the HttpResponse class has no navigation property to HttpRequest. Therefore it makes no sense to want to call GET odata/HttpResponses as we would be getting all HttpResponses, but not the HttpRequest they are linked to. In other words the HttpResponse class is useless without the context i.e. the HttpRequest for which it was produced.
The HttpResponse class not having any meaning outside of the HttpRequest context makes it a perfect candidate for OData containment. Both classes could even be saved on the same record in the database. And because it's not possible to perform a GET/POST/PUT/DELETE without specifying the id of the HttpRequest to which the HttpResponse belongs, it makes no sense for the HttpResponse class to have its own controller.
Now, back to your use case. I can see two likely domain models.
The entities User, UserAddress, Invoice and InvoiceAddress.
In this first option every single entity has their own designated address entity. OData containment would make sense here using such a design as the address entities do not exist outside of their respective parent entity. A UserAddress is always linked to a User and an InvoiceAddress is always linked to an Invoice. Getting a single UserAddress entity makes less sense because using this domain model one shouldn't care where the single address is. Instead the focus lays more on what the persisted addresses for this single User are. It's also not possible to create a UserAddress without specifying an existing User. The UserAddress entity relies on the User entity entirely.
The entities User, Invoice, TypedAddress and Address.
In this second option the Address entity is stand-alone. It exists separately from the other entities. Since an address boils down to a unique location on this planet it is only saved once. Other entities then link to the Address entity via the TypedAddress entity where they specify what kind of address it is in relation to the entity linking to it. Getting a single Address makes perfect sense using this domain model. An addressbook of the entire company could easily be retrieved by requesting GET odata/Addresses. This is where OData containment does not make sense.
Do note that it is possible to use the ODataConventionModelBuilder to configure containment. Because you do not need to add the ContainedAttribute to your class, this has the advantage of not polluting your data layer with a reference to the OData library. I would recommend this approach. In your situation I would expect to have the configuration below.
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder
.EntityType<User>()
.ContainsMany(user => user.UserAddresses);
modelBuilder
.EntityType<Invoice>()
.ContainsMany(invoice => invoice.InvoiceAddresses);
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I'll try to describe a problem that I see very often in my workplace, but I couldn't find a way or a reasonable solution to it. I searched a lot about this and all I could find is what I already have implemented. The scenario is this:
I have an ASP.NET MVC app using Entity Framework which follows the Repository Pattern. I will use a simple Student/Teacher database structure to exemplify
Entities
public class Student : BaseEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public Teacher Tutor { get; set; }
}
public class Teacher : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Student> Students { get; set; }
}
public class BaseEntity
{
public byte State { get; set; }
public Datetime CreateDate { get; set; }
public Datetime UpdateDate { get; set; }
}
Now, let's say I need to expose a method to return a list of student names along with its teacher's name:
var students = context.Students.Include(x => x.Teacher).ToList();
The query above is bad and we all know it, since it returns all columns. Now, if we refactor to this:
var students = context.Students.Include(x => x.Teacher)
.Select(x => new
{
Name = x.Name,
TeacherName = x.Teacher.Name
}).ToList();
I'll have a performant query that select only the fields I want. That's good. But now I need to make a choice. To return this list to my controller, I can either: Create a StudentDTO, or populate a Student instance with only the columns I selected in my query.
DTO approach
If I create a DTO and pass it along to my controller all will be "fine". No worries with extra unnecessary fields.
Return EF Entity Student
If I return the database entity to my controller as is, even though I loaded it with only the fields I wanted I will get all the other empty fields. So I create a ViewModel to return only the data I want. (This is what we are doing right now in most methods along with AutoMapper)
Problem:
See the pattern? Either way I will ended up creating a class to map my return. I'm fine with this most of the time, but in the project I'm working right now, we have several methods to expose and each of them has a different return structure. For example, what if I wanted to return a list of students that contains only student Id and Name? Create another DTO or ViewModel?
The project has a team of 5 developers and the ViewModel folder is getting pretty stuffed with classes. I started instructing them to return an anonymous object inside a controller when a method return is very specific. I only create View Models now when I'm sure it can be re-used elsewhere.
But this anonymous approach had become also bad because now I have to do this in several controllers and I feel I'm repeating myself.
Is there any other approach I can use to solve this? Of course the project I'm talking about is much more complex than this example, with several entities and pretty complex queries. I feel this happens a lot in other projects and I failed to find a decent way out of this.
I wish I would have stumbled upon this question a year ago. Hopefully this info helps you or someone else even though its been awhile.
You are exactly right. You see a problem and your gut is already telling you there is an architecture problem and you are right.
I know it is a pain but the DTO approach is the correct architecture in my opinion. These classes are a pain to create and use and we have all tried to shorcut around them at some point. But, you should be inheriting from base classes to share properties between objects to ease your pain. Also, use a 3rd party open source tool like automapper to move data easily between your data models and your dto objects.
Developers make this architectural mistake all the time (trying to bypass the DTO object) especially if they are working on smaller software systems and not large corporate enterprise systems where the above architecture will fail fast while it may succeed forever in a small system.
using your first example:
var students = context.Students.Include(x => x.Teacher).ToList();
You would then copy students into a dto object (perhaps StudentDTO) and then pass this up to your UX and translate it into a viewmodel object. If Student and StudentDTO are identical then they can inherit from the same base class and StudentDTO gets created with about one line of code.
Using your second example
var students = context.Students.Include(x => x.Teacher)
.Select(x => new
{
Name = x.Name,
TeacherName = x.Teacher.Name
}).ToList();
If you do not do this and instead translate everything into a ViewModel then you will end up with endless viewModels as you have.
However, even more importantly here, you shouldn't be able to move it into a viewmodel because ViewModels should sit in your UX layer and the fact that you can do this would indicate a small architecture issue on its own. ViewModels are only applicable to the UX and not anywhere else so keep them in the UX layer.
If you move your viewmodels into the UX you would find that you could not move your EF objects into your View Models and this would have steered you down the DTO architecture approach instead.
So why dont you just pass EF models up to the UX?
Well, you can. Works good in simple scenarios when you are just editing a single student for instance. This is tempting because its so easy to do and it works so why not do this?
For very simple, small systems please do. I think this is fine. you can pass an EF model up to the UX, translate it into a viewmodel and then the viewmodel back to the EF. To do this your EF models should sit outside your data and ux layers in their own layer. I typically use a dll called something like "MySoftwaremName.Common". I place all interfaces, data models and dtos in this layer and reference this layer from the UX, Service and Data layers so that DTOs and interfaces can easily be passed up and down the architecture.
My primary real world experience has shown that the primary reason you do not pass EF models directly up to the UX is Caching.
In small systems developers may not deal with this so this may work just fine. But in large systems where we are getting hit 50,000 to 100,000+ times a second caching is key.
What if you wanted to cache your student object so that it could be retrieved for the next 5 minutes without you hitting the db over and over again.
You cannot cache the EF models in ASP.NET or you will eventually encounter severe issues that are occuring randomly in your system that are hard to trace down.
You can stick the EF objects in Cache and even retrieve them from cache. However, EF entities are attached to Database Context objects and that context eventually goes out of scope and gets garbage collected by .NET. If you still have your Student object in cache after this happens and you retrieve it and try to use it (using your own example again) to get the Teacher subclass "Student.Teacher"
you will get the yellow screen of death if that Teacher object is not eager loaded and is lazy loaded By EF. Ef will try to use the context to go fetch that Teacher and there isn't one and it will blow up.
To prevent all this it is best to move your EF objects into DTOs and then you can safely tranfer this data, cache it etc without any worry.
The only pain in this architecture comes in translating DTOs to viewmodels and EF models exactly as you have stated. But as I mentioned above, using proper base classes to share fields and using something like AutoMapper or another Mapping engine will help you map quickly from DTOs to ViewModels and EF objects.
Always create a ViewModel. The ViewModel is a UI concern. your entity framework model is a domain concern. ViewModels aren't about re-use. They are about defining only what you need to satisfy the View that uses them.
I want to expose legacy .net code via WCF Data Services. But without using Entity Framework anywhere. Basically I currently populate all my models from db once every X hours and dump these models in cache. The current web services pull all the info from this cache. I now have to convert all of this to WCF Data Services, primarily to support OData protocol.
What is the simplest and quickest way out (again, no entity framework)
Below is an example of how my model currently looks like:
public class Country
{
public string CountryCode {get; set;}
public string CountryName {get; set;}
public List<State> ListOfStates {get; set;}
}
public class State
{
public string StateCode {get; set;}
public string StateName {get; set;}
}
Thanks in advance.
You need to use reflection provider instead of Entity framework provider - custom context class exposed in WCF Data Service. Just be aware that reflection provider by default expose only read only data. If you need to update data through your OData service you will also have to implement IUpdateble interface on your context class.
It's not black magic - but a bit of work.
See this WCF Data Services Advanced Topics article which shows how you could use e.g. Subsonic for your ORM.
Basically, the steps involved are:
you need to expose IQueryable<T> collections for all your classes - you could do this by having some kind of a DataModel or DataContext class that contains all those collections
If you want to be able to insert and update data, you also need:
to implement the IUpdatable interface on your "data context" to enable change tracking and handling of CUD operations
I don't want to advertise myself actually, but your problem is the same situation we had here at work. We've taken over the original toolkit developed by Jonathan Carter for mapping WCF DataServices to whatever you want them to be.
Try taking a look at http://wcfdstoolkit.codeplex.com/ and see if this solves your problem. The documentation is available through links to Jonathan's blog on how to setup & use the toolkit. But I recommend to download the september release branch, to ensure you have all bug fixes in it that I already solved.
I'm trying to learn ASPNET MVC. I've built a DbModel starting from DB structure so, under Models, I have the .edmx file that can be used to access data.
I've read that it could be good to have ViewModels classes to act between the View and the Model (useful also for single fields formatting) but I don't' understand if this is right and in which way it's better to build them. If they reproduce classes in my model I believe it is a little bit redundant, isn't it? If this is the right way, is there a way to generate automatically ViewModel classes?
A ViewModel in MVC is a model of your view. It is a property bag containing, usually of primitive types. It may seem redundant, but you are protecting yourself from future problems by decoupling your code.
As an example, given a Person object in your domain model:
public class Person
{
public string FirstName {get; set;} // John
public string LastName {get; set;} // Doe
public DateTime Birthdate {get; set;} // 01/01/1965
}
In your view, you may want to represent this in a view as a full name, age and birthday. Your ViewModel would be similar to:
public class PersonViewModel
{
public string FullName {get; set;} // John Doe
public int Age {get; set;} // 46
public int Birthday {get; set;} // January 1
}
Somewhere in your pipeline, you need to convert from domain model to the viewmodel. I have used either projection queries from the persistence layer or object-to-object mapping frameworks, such as AutoMapper.
By structuring your data this way, you can keep logic and formatting rules out of your view markup. By using a framework, such as AutoMapper, you can also standardize string formatting of dates and times, and do convention-based mappings.
Also, I generally advise having one ViewModel per View. If you need to share View/ViewModel structures or apply conditional view information, those should be separated into partial views.
If you are just starting out I would avoid trying to incorporate every best practice you can find into your early applications. It becomes very easy to try and do everything everyone says is the best practice and you lose track of just learning the fundamentals.
View Models are obviously a great way of seperating the presentation layer and the domain layer, but they serve other purposes. If you are just starting out and your applications are not terribly complicated, I would recommend keeping it simple and use your domain classes as your view model where your views are simple. This will allow you to focus more on the application.
Also, by doing this you will come across views where the simple domain model will not cut it and you will find yourself needing a ViewModel. Which will allow you to incorporate the more specific information you need for your view page (such as multiple domain objects).
By practicing without using View Models for everything, you can gain an appreciation for their benefits and decide what works best for you and your code.
A "view model" (model for a view rather than domain model) helps you separate the domain model from what is bound to the page. Is it always necessary? No, but it is useful if you have some common data shapes used on multiple views where the view will also have some additional data. Another good use is removing certain data from certain types of views (your customer should not know your margin, but your management should?). IT is not mandatory.
I understand that the "proper" structure for separation-of-concerns in MVC is to have view-models for your structuring your views and separate data-models for persisting in your chosen repository. I started experimenting with MongoDB and I'm starting to think that this may not apply when using a schema-less, NO-SQL style database. I wanted to present this scenario to the stackoverflow community and see what everyone's thoughts are. I'm new to MVC, so this made sense to me, but maybe I am overlooking something...
Here is my example for this discussion: When a user wants to edit their profile, they would go to the UserEdit view, which uses the UserEdit model below.
public class UserEditModel
{
public string Username
{
get { return Info.Username; }
set { Info.Username = value; }
}
[Required]
[MembershipPassword]
[DataType(DataType.Password)]
public string Password { get; set; }
[DataType(DataType.Password)]
[DisplayName("Confirm Password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[Email]
public string Email { get; set; }
public UserInfo Info { get; set; }
public Dictionary<string, bool> Roles { get; set; }
}
public class UserInfo : IRepoData
{
[ScaffoldColumn(false)]
public Guid _id { get; set; }
[ScaffoldColumn(false)]
public DateTime Timestamp { get; set; }
[Required]
[DisplayName("Username")]
[ScaffoldColumn(false)]
public string Username { get; set; }
[Required]
[DisplayName("First Name")]
public string FirstName { get; set; }
[Required]
[DisplayName("Last Name")]
public string LastName { get; set; }
[ScaffoldColumn(false)]
public string Theme { get; set; }
[ScaffoldColumn(false)]
public bool IsADUser { get; set; }
}
Notice that the UserEditModel class contains an instance of UserInfo that inherits from IRepoData? UserInfo is what gets saved to the database. I have a generic repository class that accepts any object that inherits form IRepoData and saves it; so I just call Repository.Save(myUserInfo) and its's done. IRepoData defines the _id (MongoDB naming convention) and a Timestamp, so the repository can upsert based on _id and check for conflicts based on the Timestamp, and whatever other properties the object has just get saved to MongoDB. The view, for the most part, just needs to use #Html.EditorFor and we are good to go! Basically, anything that just the view needs goes into the base-model, anything that only the repository needs just gets the [ScaffoldColumn(false)] annotation, and everything else is common between the two. (BTW - the username, password, roles, and email get saved to .NET providers, so that is why they are not in the UserInfo object.)
The big advantages of this scenario are two-fold...
I can use less code, which is therefore more easily understood, faster to develop, and more maintainable (in my opinion).
I can re-factor in seconds... If I need to add a second email address, I just add it to the UserInfo object - it gets added to the view and saved to the repository just by adding one property to the object. Because I am using MongoDB, I don't need to alter my db schema or mess with any existing data.
Given this setup, is there a need to make separate models for storing data? What do you all think the disadvantages of this approach are? I realize that the obvious answers are standards and separation-of-concerns, but are there any real world examples can you think of that would demonstrate some of the headaches this would cause?
Its also worth noting that I'm working on a team of two developers total, so it's easy to look at the benefits and overlook bending some standards. Do you think working on a smaller team makes a difference in that regard?
The advantages of view models in MVC exist regardless of database system used (hell even if you don't use one). In simple CRUD situations, your business model entities will very closely mimick what you show in the views, but in anything more than basic CRUD this will not be the case.
One of the big things are business logic / data integrity concerns with using the same class for data modeling/persistence as what you use in views. Take the situation where you have a DateTime DateAdded property in your user class, to denote when a user was added. If you provide an form that hooks straight into your UserInfo class you end up with an action handler that looks like:
[HttpPost]
public ActionResult Edit(UserInfo model) { }
Most likely you don't want the user to be able to change when they were added to the system, so your first thought is to not provide a field in the form.
However, you can't rely on that for two reasons. First is that the value for DateAdded will be the same as what you would get if you did a new DateTime() or it will be null ( either way will be incorrect for this user).
The second issue with this is that users can spoof this in the form request and add &DateAdded=<whatever date> to the POST data, and now your application will change the DateAdded field in the DB to whatever the user entered.
This is by design, as MVC's model binding mechanism looks at the data sent via POST and tries to automatically connect them with any available properties in the model. It has no way to know that a property that was sent over wasn't in the originating form, and thus it will still bind it to that property.
ViewModels do not have this issue because your view model should know how to convert itself to/from a data entity, and it does not have a DateAdded field to spoof, it only has the bare minimum fields it needs to display (or receive) it's data.
In your exact scenario, I can reproduce this with ease with POST string manipulation, since your view model has access to your data entity directly.
Another issue with using data classes straight in the views is when you are trying to present your view in a way that doesn't really fit how your data is modeled. As an example, let's say you have the following fields for users:
public DateTime? BannedDate { get; set; }
public DateTime? ActivationDate { get; set; } // Date the account was activated via email link
Now let's say as an Admin you are interested on the status of all users, and you want to display a status message next to each user as well as give different actions the admin can do based on that user's status. If you use your data model, your view's code will look like:
// In status column of the web page's data grid
#if (user.BannedDate != null)
{
<span class="banned">Banned</span>
}
else if (user.ActivationDate != null)
{
<span class="Activated">Activated</span>
}
//.... Do some html to finish other columns in the table
// In the Actions column of the web page's data grid
#if (user.BannedDate != null)
{
// .. Add buttons for banned users
}
else if (user.ActivationDate != null)
{
// .. Add buttons for activated users
}
This is bad because you have a lot of business logic in your views now (user status of banned always takes precedence over activated users, banned users are defined by users with a banned date, etc...). It is also much more complicated.
Instead, a better (imho at least) solution is to wrap your users in a ViewModel that has an enumeration for their status, and when you convert your model to your view model (the view model's constructor is a good place to do this) you can insert your business logic once to look at all the dates and figure out what status the user should be.
Then your code above is simplified as:
// In status column of the web page's data grid
#if (user.Status == UserStatuses.Banned)
{
<span class="banned">Banned</span>
}
else if (user.Status == UserStatuses.Activated)
{
<span class="Activated">Activated</span>
}
//.... Do some html to finish other columns in the table
// In the Actions column of the web page's data grid
#if (user.Status == UserStatuses.Banned)
{
// .. Add buttons for banned users
}
else if (user.Status == UserStatuses.Activated)
{
// .. Add buttons for activated users
}
Which may not look like less code in this simple scenario, but it makes things a lot more maintainable when the logic for determining a status for a user becomes more complicated. You can now change the logic of how a user's status is determined without having to change your data model (you shouldn't have to change your data model because of how you are viewing data) and it keeps the status determination in one spot.
tl;dr
There are at least 3 layers of models in an application, sometimes they can be combined safely, sometimes not. In the context of the question, it's ok to combine the persistence and domain models but not the view model.
full post
The scenario you describe fits equally well using any entity model directly. It could be using a Linq2Sql model as your ViewModel, an entity framework model, a hibernate model, etc. The main point is that you want to use the persisted model directly as your view model. Separation of concerns, as you mention, does not explicitly force you to avoid doing this. In fact separation of concerns is not even the most important factor in building your model layers.
In a typical web application there are at least 3 distinct layers of models, although it is possible and sometimes correct to combine these layers into a single object. The model layers are, from highest level to lowest, your view model, your domain model and your persistence model. Your view model should describe exactly what is in your view, no more and no less. Your domain model should describe your complete model of the system exactly. Your persistence model should describe your storage method for your domain models exactly.
ORMs come in many shapes and sizes, with different conceptual purposes, and MongoDB as you describe it is simply one of them. The illusion most of them promise is that your persistence model should be the same as your domain model and the ORM is just a mapping tool from your data store to your domain object. This is certainly true for simple scenarios, where all of your data comes from one place, but eventually has it's limitations, and your storage degrades into something more pragmatic for your situation. When that happens, the models tend to become distinct.
The one rule of thumb to follow when deciding whether or not you can separate your domain model from your persistence model is whether or not you could easily swap out your data store without changing your domain model. If the answer is yes, they can be combined, otherwise they should be separate models. A repository interface naturally fits here to deliver your domain models from whatever data store is available. Some of the newer light weight ORMs, such as dapper and massive, make it very easy to use your domain model as your persistence model because they do not require a particular data model in order to perform persistence, you are simply writing the queries directly, and letting the ORM just handle the mapping.
On the read side, view models are again a distinct model layer because they represent a subset of your domain model combined however you need in order to display information to the page. If you want to display a user's info, with links to all his friends and when you hover over their name you get some info about that user, your persistence model to handle that directly, even with MongoDB, would likely be pretty insane. Of course not every application is showing such a collection of interconnected data on every view, and sometimes the domain model is exactly what you want to display. In that case there is no reason to put in the extra weight of mapping from an object that has exactly what you want to display to a specific view model that has the same properties. In simple apps if all I want to do is augment a domain model, my view model will directly inherit from the domain model and add the extra properties I want to display. That being said, before your MVC app becomes large, I highly recommend using a view model for your layouts, and having all of page based view models inherit from that layout model.
On the write side, a view model should only allow the properties you wish to be editable for the type of user accessing the view. Do not send an admin view model to the view for a non admin user. You could get away with this if you write the mapping layer for this model yourself to take into account the privileges of the accessing user, but that is probably more overhead than just creating a second admin model that inherits from the regular view model and augments it with the admin properties.
Lastly about your points:
Less code is only an advantage when it actually is more understandable. Readability and understand-ability of it are results of the skills of the person writing it. There are famous examples of short code that has taken even solid developers a long time to dissect and understand. Most of those examples come from cleverly written code which is not more understandable. More important is that your code meets your specification 100%. If your code is short, easily understood and readable but does not meet the specification, it is worthless. If it is all of those things and does meet the specification, but is easily exploitable, the specification and the code are worthless.
Refactoring in seconds safely is the result of well written code, not it's terseness. Following the DRY principle will make your code easily refactorable as long as your specification correctly meets your goals. In the case of model layers, your domain model is the key to writing good, maintainable and easy to refactor code. Your domain model will change at the pace at which your business requirements change. Changes in your business requirements are big changes, and care has to be taken to make sure that a new spec is fully thought out, designed, implemented, tested, etc. For example you say today you want to add a second email address. You still will have to change the view (unless you're using some kind of scaffolding). Also, what if tomorrow you get a requirements change to add support for up to 100 email addresses? The change you originally proposed was rather simple for any system, bigger changes require more work.