Custom Display Names for Child Object's properties - c#

I'm following along the ASP.NET MVC 5 book, but I've ran into an itch that the book doesn't seem to scratch. I have an Album model as so:
namespace MvcMusicStore.Models
{
public class Album
{
public virtual int AlbumId { get; set; }
public virtual int GenreId { get; set; }
public virtual int ArtistId { get; set; }
public virtual string Title { get; set; }
public virtual decimal Price { get; set; }
public virtual string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
}
To make a long story short, the Genre and Artist models both have a field called Name. When I list these using the StoreManagerController, it displays simply as "Name" in each of the headers. I can add a DataAnnotation to Genre and Artist suchs as [Display(Name="Artist Name")], but I only want it to display as "Artist Name" in this particular instance. I don't want it to be so specific when I am on the "Edit Artist Page."
I understand that I should go about doing this by using a ViewModel, but I am still confused as the view model would still just be pulling in the object, and that object's Display annotations are set in the model itself.
Or better yet, is this something that's best left to the markup?

Not if you use view models properly. Many people end up creating view models like:
public class FooViewModel
{
public Foo MyFoo { get; set; }
}
That's just a waste of time. Instead, you view models should completely stand in for whatever entity your editing, which means, instead of just referencing the entity, you create properties in your view model for all the properties in your entity that you want to view/edit. Then, in your controller actions, you "map" to and from your entity and view model, which is to say, you just set the properties on one with the values of the appropriate properties on the other.
In your situation then, you would need something like:
public class AlbumViewModel
{
public string Title { get; set; }
public decimal Price { get; set; }
public string AlbumArtUrl { get; set; }
public GenreViewModel Genre { get; set; }
public ArtistViewModel Artist { get; set; }
}
public class ArtistViewModel
{
public string Name { get; set; }
...
}
public class GenreViewModel
{
...
}
Then, you can set the display name to be whatever you want on this view model. If you need a different display name in another context, create a separate view model for that.
Also, what's up with all the virtuals? The virtual keyword merely means that the property/method can be overridden by a subclass. While it technically doesn't hurt anything to just make everything virtual, it's code smell unless you truly intend something to be overridden, or even subclassed in the first place. Traditionally, on entities, the only thing you'll ever add virtual to is navigation properties, as this allows Entity Framework to apply its lazy loading logic to your entity. (It literally creates subclasses of your entities dynamically, called "proxies", that add the lazy loading logic to the navigation properties' getter.) If you don't have a navigation property or even if you just don't want lazy loading enabled for that navigation property, then you shouldn't use virtual, unless you really mean to.

I would probably do something like this.
public class AlbumViewModel
{
public int AlbumId { get; set; }
public AlbumGenre Genre { get; set; }
public AlbumArtist Artist { get; set; }
}
[MetadataType(typeof(AlbumArtistMetadata))]
public class AlbumArtist : Artist {
private class AlbumArtistMetadata {
[Display(Name="Artist Name")]
public string Name { get; set; }
}
}
[MetadataType(typeof(AlbumGenreMetadata))]
public class AlbumGenre : Genre
{
private class AlbumGenreMetadata
{
[Display(Name = "Genre Name")]
public string Name { get; set; }
}
}
Though I'm not sure I'd inherit from the entities, but instead create models based on the entities.

Related

ViewModel Structure Decision

As my domain classes I have Person and FavoritePerson classes as follows.
public class CompanyPerson : ICompanyPerson
{
[Key]
public Guid PersonId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
public class CompanyFavoritePerson : IFavoritePerson
{
[Key]
public Guid FavoritePersonId { get; set; }
[Column(TypeName = "datetime2")]
public DateTime CreateDate { get; set; }
public Guid? CompanyPerson_PersonId { get; set; }
[StringLength(128)]
public string CompanyUser_UserId { get; set; }
public virtual CompanyPerson CompanyPerson { get; set; }
public virtual CompanyUser CompanyUser { get; set; }
}
In my web application I will need to show List of Favorite Person. So my view model is like this;
public class FavoritePersonViewModel
{
public Guid FavoritePersonId { get; set; }
public DateTime CreateDate { get; set; }
public Guid? CompanyPerson_PersonId { get; set; }
public string CompanyUser_UserId { get; set; }
//Option1: PersonViewModel PersonViewModel {get; set; }
//Option2: public string Title {get;set;}
}
Since I need to show Title of the favorite user in the list (where title belongs to Person class) which way will match with best practices?
Referencing a viewModel from another viewModel or extend viewModel with required extra attributes and fill them in business layer?
After some more research on this topic; I found out at this question
What is ViewModel in MVC?
it is clearly stated that:
View models can combine values from different database entities.
As like below;
So now you have data from the Employees and Departments tables in one
view model. You will just then need to add the following two
properties to your view model and populate it with data:
public int DepartmentId { get; set; }
public IEnumerable<Department> Departments { get; set; }
So I am going with Option 2.
The ViewModel pattern is just one of many patterns that fall into the 'Separated Presentation Pattern' bucket.
It's very important that you think about the requirements of your view before designing the ViewModel. For instance, if you have two widgets in your view and every widget has its own ViewModel, composite ViewModel is suitable in the situation, but if the view is just one that uses multiple domain classes, whether you have View model for each one, composite ViewModel is not suitable because it increases the complexity and every change in one ViewModel can break your code.
Thus, based upon your question
As my domain classes I have Person and FavoritePerson classes.
Since I need to show Title of the favorite user in the list (where title belongs to Person class).
It seems to me that composite ViewModel is not a good choice and you should design a new ViewModel.
It is also worth to read the ViewModel Best Practices

Entity Framework - Code First - Map results to Not Mapped properties

I have created these entities Product, Order, OrderedItem in EF using Code First.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[NotMapped]
public int IssuedQuantity { get; set; }
[NotMapped]
public int InhandQuantity { get; set; }
public virtual ICollection<OrderedItem> OrderedItems { get; set; }
...
}
public class Order
{
public int Id { get; set; }
public string ReferenceNumber { get; set; }
public virtual ICollection<OrderedItem> OrderedItems { get; set; }
...
}
public class OrderedItem
{
public int OrderId { get; set; }
public string ProductId { get; set; }
[ForeignKey("OrderId")]
public virtual Order Order { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
...
}
Now I want to get all products by passing current user id to a stored procedure. It will then return all products along with total product quantity currently in user's hand.
The problem is that EF is not mapping SP results back to Product entity for NotMapped properties. i.e. all properties in product entity have values but NotMapped properties are set to NULL even when I return their values from SP.
What I want to ask is that does EF support this kind of functionality? If yes then how?
NOTE I know about Computed Properties but that will create unneccessary columns in tables and I don't want that, since these properties are calculated at run-time.
NOTE I know that I don't need to create OrderedItem entity. But I am storing some other properties in it, which are removed here for brevity.
I'm quite sure that EF does not support dynamic mapping (you could try to change the mapping metadata but is not a clean way or delete the mapping cache but then EF will be very slow). In this case the razionale is that the entity are 2 different entities because they have different data. In your case probably the best thing is to do 2 entities the ProductWithQuantities that inherits from Product.
BTW Thinking about ERPs, the model of orders/wms usually is different. Products does not contain informations about QtyOnHand or sales/buy information. Usually is another object (Inventory?) that contains this informations.
I would create a View Model of the product with all the required properties and pass that to the view instead of the Product model. Then you are not constrained by the mappings of the Product model and you do not have to use the [NotMapped] Attribute on the fields.
[NotMapped]
public class ProductVM
{
public int Id { get; set; }
public string Name { get; set; }
public int IssuedQuantity { get; set; }
public int InhandQuantity { get; set; }
public virtual ICollection<OrderedItem> OrderedItems { get; set; }
...
}
I hope that helps.

Entity Framework Include without nested properties

I have two related entities called DataTag and TagSource that look like the following:
public class DataTag : BaseModel
{
[Column("DataTagId")]
public override Guid ID { get; set; }
public string Tag { get; set; }
public Guid TagSourceId { get; set; }
public TagSource TagSource { get; set; }
}
public class TagSource : BaseModel
{
[Column("TagSourceId")]
public override Guid ID { get; set; }
public string Description { get; set; }
public bool IsInternal { get; set; }
public string Source { get; set; }
public ICollection<DataTag> DataTags { get; set; }
}
I am allowing the user to Include the navigation properties through the url like "/api/DataTags?Include=TagSource". The problem is when I include the TagSource, it also includes the collection of DataTags in that object which I don't want unless the user specifies it (For example "/api/DataTags?Include=TagSource.DataTags". Is there any way to stop that property from being loaded when I include the TagSource? I have tried making the properties virtual and turning lazy loading off globally but that didn't work. The reason I haven't marked them virtual is because I am using AutoMapper and I only want to include the navigation properties that the user specifies.
As in the comments you need to create a DTO object. There is a good article here detailing how to do this with WebAPI
http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-5
Edit.
The problem with this is you will need a lot of different DTO objects for each possible outcome which could become messy. If your return type is JSON you can add this attribute to your properties:
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Firstly : Apologies for my English.
Secondly : I had the same issue with a code first database model that creates foreign keys this way : public virtual Collection<Object> Objects {get; set;}
and I found a workaround by setting the property setter as private:
public virtual Collection<Object> Objects {get; private set;}
Then the EF cannot populate the Objects collection because with a private set you can only assign a value in constructors.

Model and partial model, how to avoid the redundant code?

I have a model and a partial model which contains only the properties that I need to expose in JSON.
But the properties between the model and his partial model are redundant.
How can I avoid that or improve my approach?
namespace Dashboard.Models.UserModels
{
public class UserModel
{
public int id { get; set; }
public string dbName { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public int idExternal { get; set; }
public int idInstance { get; set; }
public string login { get; set; }
public string password { get; set; }
public DateTime? dtContractStart { get; set; }
public DateTime? dtContractEnd { get; set; }
public string emailPro { get; set; }
public string emailPerso { get; set; }
public LuccaUserModel()
{
idInstance = -1;
}
// partial model for json result
// not sure is the best way or have to be here
public class PartialUserModel
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string emailPro { get; set; }
public string emailPerso { get; set; }
public DateTime? dtContractStart { get; set; }
public DateTime? dtContractEnd { get; set; }
public string url { get; set; }
}
// UserModel Methods
}
}
You can rename PartialUserModel UserModelBase class (or leave it as is... it just makes better logical sense to do so) and make UserModel to inherit from it:
public class UserModel : UserModelBase
{
...
}
Of course you'll need to remove all duplicate properties from UserModel in this case.
It's a thin line between doing a proper design and building an overkill design. Answer depends on many inputs, among which I chose to have project and model breadth most important.
In hope to have my answer clearer, I have to say I use different terminology. Data which is adopted for use in UI is usually called ViewModel. In your case, you would build UserViewModel which contains necessary subset of information.
If I'm working on a one-off project, I'll reuse model as a ViewModel. I'll do this by having helper method which removes sensitive information, loads up or cuts off data which is lazy loaded from database and does other preparation on data. All this is done with same model class.
If it's not a short term project, I look to create separate ViewModel classes which I map from model data. Then, if I'm working with mostly flat data I use AutoMapper tool to have data automatically copied, instead of writing my own mappers.
As another answer here states, you write a basic class with data you need in UI and extend it with other model data, however this is not a good approach for several reasons.
If violates separation of concerns. Project dealing with model and persistance should not know about your ViewModel
You may need to flatten data from related objects into ViewModel objects. In that case, your model objects would have fields which should not be there, or would be redundant.
You may need calculated fields and helper methods in ViewModel which would again end up in model, confusing everyone that is not updated about design.
You could want to adopt several unrelated model classes to same ViewModel class
To try and put it shortly, either reuse model class or create ViewModels. There is unfortunately no clever solution. If you find one, please post a comment as I'd like to hear about it :)

Entity Framework Class / Database Schema advice needed

I asked a question recently, and quite frankly, from the answer that was given, I am second guessing my entire strategy/how I design the classes and database.
I have not yet used the virtual keyword, nor Icollection at all in any of my Entity Framework projects, and quite frankly, after reading about it in some of the examples I do not fully understand why it is needed, or how it works.
In a sample application, I have a simple design where there are three lists - people, notes and pictures. The relationships are such that a person can own multiple notes and pictures, as well as people having a logo which is a picture.
public class Person
{
public int ID { get; set; }
public string name { get; set; }
public Picture logo { get; set; }
}
public class Note
{
public int ID { get; set; }
public string Text { get; set; }
public Person Owner { get; set; }
}
public class Picture
{
public int ID { get; set; }
public string Path { get; set; }
public Person Owner { get; set; }
}
When I want to select a list of notes that a person owns, I simply perform db.Notes.Where(x=>x.owner=="y") on the notes object. I think I understand that if I were to use Icollection on the person class, I could instead perform something along the lines of db.person.select(x=> x.notes) to retrieve all the notes. Am I correct in this thinking?
If you were in my position with the relatively simple example above, how would you build the classes (involving ICollection, virtual or anything else)?
In addition and most importantly, the above is just an example, however in my actual application, I have used a very similar structure where I use my custom type as the "connector"/Foreign Key.
In many examples I have been reading, (in the above example) they would be using public int OwnerID instead of public person Owner. This has really thrown me and I am questioning my entire EF strategy. What are the differences?
Any advice would be greatly appreciated.
I think you are making this more difficult that is needed. If you were laying out regular classes you would relate them to each other rather than finding related id's and loading them separately which you are doing in your example.
public class Person
{
public int ID { get; set; }
public string name { get; set; }
public ICollection<Note> Notes { get; set; }
public ICollection<Picture> Pictures { get; set; }
public Picture logo { get; set; }
}
public class Note
{
public int ID { get; set; }
public string Text { get; set; }
public Person Owner { get; set; }
}
public class Picture
{
public int ID { get; set; }
public string Path { get; set; }
public Person Owner { get; set; }
}
So now say you have gotten your person object using the query
var person = _context.People.Where(m=>m.ID=randomIntWeWant).First();
We can get all related items as properties.
For Notes
person.Notes
For Photos
person.Photos
ICollection is related to lazy loading. By declaring a property as ICollection on one side, your are saying you have a many-to-one relationship between the objects. If you declare a property as ICollection on both sides, you are saying it is a many-to-many relationship. EF takes care of creating the tables that track that relationship.

Categories

Resources