I have a following model class:
public class Class1
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Class1> Class1s{ get; set; }
}
Now I want to add one more property to my model that will be
public string NewProp { get; set; }
I know very well to achieve this by code , but is there any way to add this dynamically?
in simple I want to make a UI who ask me about property name as well as datatype when I submit values it automatically add the property to my existing model. I am using EntityFramework Code-First. However since I have already the DB, I can also use the DB-First approach if the solution is using DB-First.
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 have a need for a project to allow the user to setup database info and table names in the config file. I want to use ADO.NET Entity Model to use the LINQ and just stay away from SQL the most I can to make it easier on myself. Is there a way to dynamically assign what table a Class needs to access for the modal?
For example:
This is what it looks like normally
[Table("database.table")]
public partial class table
{
[Key]
[Column(TypeName = "usmallint")]
public int ID { get; set; }
[Required]
[StringLength(128)]
public string Instance { get; set; }
[Required]
[StringLength(60)]
public string Name { get; set; }
}
I want to be able to dynamically set the TableAttribute so the model knows what table to access for the class.
[Table(Config.DBName + Config.tableName)]
public partial class table
{
[Key]
[Column(TypeName = "usmallint")]
public int ID { get; set; }
[Required]
[StringLength(128)]
public string Instance { get; set; }
[Required]
[StringLength(60)]
public string Name { get; set; }
}
Any help or letting me know that it is not possible would be appreciated.
I've not tested this, but I think you can do this via implementing custom conventions - if you're using EF6 at least.
First, you need to create a custom Convention:
public class CustomTableNameConvention : IStoreModelConvention<EntitySet>
{
private readonly string _tablePrefix;
public CustomTableNameConvention(string tablePrefix)
{
_tablePrefix = tablePrefix;
}
public void Apply(EntitySet item, DbModel model)
{
//change table name.
item.Table = $"{_tablePrefix}" + item.Table;
}
}
Next, you need to add this convention in the OnModelCreating method of your Context:
public class MyContext : DbContext
{
public MyContext(string connectionString) : base(connectionstring)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//get the dynamic table prefix...
var myAppPrefix = "user1";
modelBuilder.Conventions.Add(new CustomTableNameConvention(myAppPrefix));
base.OnModelCreating(modelBuilder);
}
public DbSet<SomeModel> { get; set; }
...
}
... Then, whenever the model in this application instance starts up, it should run through the above when deciding what the table name(s) should be.
Just replace the myAppPrefix = ... code with a call to an appropriate service to get the prefix for this instance.
the obvious caveat with this is that you cannot use a value for the prefix which is returned from the database (at least, not via this Context), as the Context isn't yet initialised.. so you'd have to either store it in settings or pass it in some other way.
Hope this helps.
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 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 entity class in created using entity framework which is in my Domain project
using System;
using System.Collections.Generic;
public partial class Test
{
public int Id { get; set; }
public int ExamID { get; set; }
public string TestName { get; set; }
public string StartDescription { get; set; }
public string EndDescription { get; set; }
}
And In my MVC application I am creating one viewmodel which I use in my view
public class TestViewModel
{
public Test Test { get; set; }
}
Now I want to make fields related to "StartDescription" and "EndDescription", for this is am trying to use TinyMCE.
Now the problem is "[AllowHtml]" attribute is in mvc but my real entity is in other project
I am following this tutorial.
http://www.codeproject.com/Articles/674754/TinyMCE-and-ASP-NET-MVC-advanced-features
Rather than your view model having an instance of Test it should contain the properties you wish to use in the view. You can then add the [AllowHtml] attribute to the properties in your view model without affecting your domain objects.
public class TestViewModel
{
public int Id { get; set; }
[AllowHtml]
public string StartDescription { get; set; }
[AllowHtml]
public string EndDescription { get; set; }
}
In your controller you would then need to map the view model to your domain class.
Old post but thought this might be relevant for someone else:
borrowing a sample code from petelids and modifying it.
public class TestViewModel
{
public int Id { get; set; }
[UIHint("tinymce_jquery_full"), AllowHtml]
public string StartDescription { get; set; }
[UIHint("tinymce_jquery_full"), AllowHtml]
public string EndDescription { get; set; }
}
Providing the UIHint on the model object you can place your tinyMCE script code in a file saved in the Folder
~/Views/Shared/TemplateEditor
I do this using the TinyMCE4.MVC libraries - however mine is modified a bit for my own special workings that I have added.