I have two classes below, Form and FormFieldOption<T>. The latter is intended to represent a set of <option> inside of a <select> in a web form that the Form object represents.
public class Form
{
public int Id { get; set; }
public FormFieldOption<string> Status { get; set; }
public FormFieldOption<string> Category { get; set; }
public FormFieldOption<int> Severity { get; set; }
}
public class FormFieldOption<T>
{
public int Id { get; set; }
public string Description { get; set; }
public bool Active { get; set; }
public T Value { get; set; }
}
I'm working on configuring these entities for Code-First like below:
public class FormFieldOptionStringConfiguration : EntityTypeConfiguration<FormFieldOption<string>>
{
public FormConfiguration()
{
//configure here
}
}
Unfortunately at this point I've discovered that I would like there to be a difference between the configuration for the Status and Category properties. I've not been able to figure out a way top configure the properties that utilize the FormFieldOption class individually. How could I do this?
Solutions I've come up with:
Create a new class that inherets FormFieldOption<T> for each property and configure individually.
Create an interface IFormFieldOption<T> and implement classes individually for each use.
I don't particularly care for either of these options as it feels like a lot of duplicated code just to create a different configuration for each table.
It turns out that you can't do this. What I ended up doing was creating a generic interface that I implemented for each property.
Related
As a newbie with ASP.NET MVC pattern, I'm trying to create a small web application in order to practice knowledge learned through some tutorials.
I have some obscure things about Model and ViewModel. I understand that Model defined only the table structure whereas ViewModel defined the logic for data, How to handle data... Furthermore, ViewModel is used when I want to display more than one model into my View.
Well, it's very theoretical and I'm trying to develop this with my application.
My application:
This application lets to handle projects and people. I can create a new project object containing some properties: project name, project location, ... and add a list of people who will work on this specific project.
Then, in the other side, I have a simple people table with properties like : Firstname, Lastname and function.
When I create a new project, I would like to select one or multiple people in order to attach them to the project.
My class People:
I created a simple class which looks like this:
public class People
{
public int PeopleID{ get; set; }
public string Lastname { get; set; }
public string Firstname { get; set; }
public string Job{ get; set; }
}
I removed Annotations in order to see clearer my class.
I created the CRUD associated and it works fine.
My class Project:
In this class, I define properties from project object and I would like add a list of people collaborating on the project.
I have:
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public List<People> ListOfPeople { get; set; }
}
If I understand, now I have to create a ViewModel in order to create my Project object with information from Project and People classes ?
My class ProjectPeopleVM:
This class is identical as Project class ?
So I have:
public class ProjectPeopleVM
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public List<People> ListOfPeople { get; set; }
}
Is it right ? I have some doubts about this.
If I want to create a controller class which let to Create a new object Project, I have to fill the ListOfPeople by using EF ? Something like db.People.ToList() ?
public class ProjectsController : Controller
{
private MyAppContext db = new MyAppContext();
public ActionResult Create()
{
var people_list = db.People.ToList();
var project = new ProjectPeopleVM
{
ListOfPeople = people_list;
// What I need to add here ? Data to populate ListOfPeople come from people_list variable
}
return View(project);
}
I'm a bit lost.
It's not necessary that you create a duplicate of your class just to see the information but it seems that in your code, you might need to because;
I noticed that in your Project Model, you didn't use public virtual List<People> or the virtual keyword, which is used for "lazy loading". When an existing project is taken from the db context, if you have the virtual keyword on your property, then it would automatically load the associated object. On the other hand, if you don't have it, then you will need to manually assign the list. Using lazy loading might have a little effect on the performance but with this you can view the properties of your child class immediately.
If your list has virtual property,
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public virtual List<People> ListOfPeople { get; set; }
}
Then in your controller or view, you could navigate to the properties of the objects in that list;
// this will give the first name of the first person on the first project
db.Project.FirstOrDefault().ListOfPeople.FirstOrDefault().FirstName;
For your create action in your controller, since it's a new Project, it doesn't have any People in it. Hence you will need to manually populate that list. To populate it, since you only need specific people, I suggest to use a checkbox or multiple input fields (aided with javascript).
The ListOfPeople can be populated by having a form element;
<input name="ListOfPeople[1].PeopleId" value="1"/>
<input name="ListOfPeople[1].FirstName" value="Mark"/>
<input name="ListOfPeople[1].LastName" value="Jacob"/>
<input name="ListOfPeople[1].PeopleId" value="2"/>
<input name="ListOfPeople[2].FirstName" value="Red"/>
<input name="ListOfPeople[2].LastName" value="Wandersee"/>
When you submit the form, the values will be bound to the Project model's ListOfPeople. Then that's the time you will need to loop through it and create a ProjectPerson (junction) record which determines where this person belongs to.
foreach(var i in model.ListOfPeople){
ProjectPerson pp = new ProjectPerson();
... // do property assignment
db.ProjectPerson.add(pp);
}
your view models should be used to map a combination of data drawn from the db. i.e.
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public IColleciton<People> ListOfPeople { get; set; }
}
public class People
{
public int Id{ get; set; }
public string Name{ get; set; }
public virtual Project project { get;set; }
}
this will allow relational retrieval from EF
viewModel should be used when you need a combination of this data without relationship i.e.
public class Project
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
}
public class People
{
public int Id{ get; set; }
public string Name{ get; set; }
}
public class ProjectVm
{
public int ProjectID { get; set; }
public string ProjectName{ get; set; }
public string ProjectLocation{ get; set; }
public ICollection<People> ListOfPeople { get; set; }
}
you can use a tool such as automapper to set up the mapping between objects which will generate custom model inside controller.
see this article: http://bengtbe.com/blog/2009/04/14/using-automapper-to-map-view-models-in-asp-net-mvc/
and DB Relationships
https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/conventions/built-in
I am creating some view models for my ASP MVC web app.
I created "code first" models for database. Is it a good way to derive view models from database models?
Example database model:
public class Project
{
[Key]
public int Id { get; set; }
public int? CustomerId { get; set; }
public int TypeId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
View model:
public class ViewModelProject : Project
{
[NotMapped]
public DateTime? Start { get; set; }
[NotMapped]
public DateTime? End { get; set; }
[NotMapped]
public string Manager { get; set; }
}
Is this the right way or is it completely false?
EDIT (subquestion):
I have some very simple database models like ProjectType, which only contains i.e. two properties. Should I also fragment those models in model view or can I make it that way:
Simple database model:
public class ProjectType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Code { get; set; }
}
Can I use it like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public ProjectType Type { get; set; }
}
Or does it have to be fragmented like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int TypeCode { get; set; }
}
I would not recommend doing it this way. I (and many others) have tried it and it doesn't work well. You will inadvertedly run into troubles, since an MVC model has to be tailored to the view and what you get from the DB rarely fits. Sure, you can hammer it into place, but the code quickly gets messy and store-related and UI code starts to mangle together. This even shows in your example, since you have to put the NotMappedAttribute (which is related to data storage), to ViewModelProject (a class at UI level).
There are many other examples to show this problem, but an especially good one I find when you want to serialize a model object to JSON and send it to a JavaScript client. The JSON serializer takes the values of all public properties and adds them to the JSON. If you want to exclude a property, you have to mark it with a ScriptIgnoreAttribute, which you would also have to apply to the base class, which breaks separation between UI and store-related code.
The better way to go is to keep the staorage model and the MVC model separated and to map the data from one to the other (there are already pre-existing frameworks that help you with that, such as Automapper). This comes with additional advantages, for example better testability, since you are now not dependent on a specific data store to create model instances.
I'm working on a recommendation algorithm which all works fine. But now I wanted to implement this code into the branch of my development team.
I'll start from the top. My algorithm can recommend 2 types of objects, restaurants and dishes.
Restaurant:
public class Restaurant
{
public Guid Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public List<Tag> Tags { get; set; } = new List<Tag>();
public int PriceRange { get; set; }
}
And dish:
public class Dish
{
public Guid Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public virtual Restaurant rest { get; set; }
[ForeignKey("rest")]
public Guid RestaurantId { get; set; }
public List<Tag> Tags { get; set; }
}
Now my product owner wants the list to be like this when it's being presented on the home page of our app:
[Restaurant][Dish][Restaurant][Dish] Etc...
So basically, he wants to alternate the type of object that's being recommended. These dishes and restaurants are completely separate. They are generated by my algorithm purely on the user's preferences and have no correlation with eachother at all.
Now my problem is how to return such a list. I figured I'd need a wrapper class which contains either a Restaurant or Dish like this:
public class RecommenderItem
{
public Restaurant rest { get; set; }
public Dish dish { get; set; }
}
This way I can create a List<RecommenderItem> and return that to the client. The client would only need to check which attribute is null and retrieve the values from the one that is not.
I'm just unsure if this is the correct approach. Are there any 'best practices' in doing this? Let me know if I should elaborate more!
If they doesn't have common base class then creating one wrapper class is the best solution. At the same time you can be more flexible and create something like
public class RecommendationItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public string PageUrl { get; set; }
public object Entity { get; set; }
}
So you can include all common information in this class and client will not be required to check with which object type he works. In such case it would be easier to add one more item type. At the same type I added reference to entity itself - it can be used if some specific handling for one or two item types is required.
You can declare an interface IRecommenderItem:
public interface IRecommenderItem
{
//shared properties
}
public class Restaurant : IRecommenderItem
{
}
public class Dish : IRecommenderItem
{
}
than, you can type:
List<IRecommenderItem> m = new List<IRecommenderItem>();
If you are going to connect pairs of elements it always makes sense to me to... well, pair the elements. I am assuming that each dish is specific to a particular restaurant? So the list would be [Restaurant1][Dish for Restaurant1][Restaurant2][Dish for Restaurant2]...?
I like the previous answer by oryol creating a common base class as well.
So, your RecommenderItem class is fine. But fill in both properties and pass a list of pairs back. Expand the list into the full set of items for display by creating a new List, iterating through the list of RecommenderItems and adding Restaurant and Dish from each entry in it.
I'm trying to implement database structure in which there are common fields i put them in a separate abstract class but i want to know if 3 classes are inheriting from same abstract class and 2 have same property name so, by default entity framework will add a numeric followed by property name in database. Is there any way to implement this separately. I've studied complex types and searched over internet but couldn't find any flexible solution. I'm sharing my code, please guide me
public abstract class GenericImpression
{
[Key]
public int ImpressionId { get; set; }
public DateTimeOffset ReportingDate { get; set; }
}
public class Impression : GenericImpression
{
public string InventorySource { get; set; }
public string Media { get; set; }
}
public class Impression21 : GenericImpression
{
public string InventorySource { get; set; }
}
Now, EF will add one table with InventorySource1 and InventorySource Column.
Use OfType<>.
Example:
_context.GenericImpressions.ofType<Impression21>().ToList()
I have the following classes in my Model:
public abstract class Entity : IEntity
{
[ScaffoldColumn(false)]
public int Id { get; set; }
[Required,StringLength(500)]
public string Name { get; set; }
}
and
public class Model : SortableEntity
{
[Required]
public ModelType Type { get; set; }
[ListRequired]
public List<Producer> Producers { get; set; }
public List<PrintArea> PrintAreas { get; set; }
public List<Color> Colors { get; set; }
}
To display the "Model" class in the view I simply call Html.EditorFor(model=>model), but the "Name" property of the base class is rendered last, which is not the desired behaviour.
Is it possible to influenece on the order of displayed fields somehow?
I've not been able to find an attribute for that, so your options are:
1) create one, and then revise the base Object.ascx template to account for it, or
2) create a custom editor template for your classes that explicitly put stuff in the order you want.