I have a MachineSettings entity and this entity has a Machine entity as a foreign key.
public class Machine
{
[Key]
public int MachineId { get; set; }
[Required]
[Display(Name = "Machine Type")]
public string MachineName { get; set; }
}
public class MachineSettings
{
[Key]
public int MachineSettingId { get; set; }
[Required]
public string Password { get; set; }
[Required]
public int ReferenceKeyLength { get; set; }
[Required]
public virtual Machine MachineId { get; set; }
}
In my controller class, when I created an Edit method as POST:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MachineSettings machineSettings)
{
if (ModelState.IsValid)
{
db.Entry(objapp).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(machineSettings);
}
On the page I have shown the list of machines in drop down list, when do the changes and select another machine in dropdown and click on save. The Edit method is called with a MachineSetting object. Here my ModelState.IsValid always false.
On checking the object in debug mode, I am getting the MachineId from the drop down, but MachineName is not returned, so how to avoid MachineName checking in this so that ModelState.IsValid property will be true?
try to fix the classes
public class MachineSettings
{
[Key]
public int MachineSettingId { get; set; }
[Required]
public string Password { get; set; }
[Required]
public int ReferenceKeyLength { get; set; }
[Required]
public int? MachineId { get; set; }
public virtual Machine Machine { get; set; }
}
public class Machine
{
[Key]
public int MachineId { get; set; }
[Required]
[Display(Name = "Machine Type")]
public string MachineName { get; set; }
public virtual ICollection<MachineSettings> MachineSettings { get; set; }
}
and create view model for the view
public class MachineViewModel
{
public MachineSettings MachineSettings {get; set;}
public IEnumerable<SelectListItem> Machines { get; set; }
}
and action
public ActionResult Edit(MachineViewModel viewModel)
Maybe you should use a specific class for your ViewModel. ViewModels are for Views(UI) <--> Controller intercommunication, and usually are diferrent classes than the persistance (EF) layer. So your ViewModel doesn't even needs a full Machine property. Could be something like that:
public class MachineSettingsViewModel
{
public int MachineSettingId { get; set; } // Only if you are using the ViewModel for edit
[Required]
public string Password { get; set; }
[Compare("Password")]
public string ConfirmPassword { get; set; }
[Required]
public int ReferenceKeyLength { get; set; }
[Required]
public int MachineId { get; set; }
public IEnumerable<SelectListItem> Machines { get; set; } // Collection with the options for the machine selector. Must be filled in the controller from query to service or DB
}
The ViewModel may include properties only used in the view, or needed for form validation but not needed in the DB.
In the controller "Get" action, you create and fill the viewmodel, then you pass it yo the view, and in the "Post" method you validate the viewmodel and convert it to a entity to be saved in the DB.
Take a look at What is ViewModel in MVC?. It's a more detailed explanation of ViewModels vs Models.
Related
I Have an Model"TClientsAdmins" and ViewModel is TClientsAdminsViewModel.I want read all records from DB where filtered by id.
I Read they from domain model and when I want Map to viewmodel I get zero Count in viewmodel.
In addition I have a model that is called THoldingAdmins That is associated with TClientsAdmins.
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[StringLength(50)]
public string CompanyName { get; set; }
public int? THoldingAdminsId { get; set; }
public virtual THoldingAdmins THoldingAdmins { get; set; }
and TClientAdminViewModel :
public int Id { get; set; }
[StringLength(50)]
public string CompanyName { get; set; }
public int? THoldingAdminsId { get; set; }
public virtual THoldingAdminsViewModel THoldingAdmins { get; set; }
and THoldingAdmins:
public byte[] Logo { get; set; }
public bool IsDeleted { get; set; }
public virtual List< TClientsAdmins> TClientsAdmins { get; set; }
and AutoMapper Configuration :
Mapper.CreateMap<TClientsAdminsViewModel, TClientsAdmins>();
Mapper.CreateMap<List<TClientsAdminsViewModel>,List<TClientsAdmins>>();
You don't need an explicit mapping for IList, but it does look like you have your mapping the wrong way round, if you're mapping from Model to ViewModel. Try
Mapper.CreateMap<TClientAdmins, TClientAdminsViewModel>();
Mapper.CreateMap<THoldingAdmins, THoldingAdminsViewModel>();
I am trying to create my first app using ASP.NET MVC framework and Entity Framework 6.
I chose to use code first approach and I started by defining my Models.
I have a model called Client with an identity attribute called Id. I have multiple Models that has an attribute called ClientId. The ClientId attribute should have virtual link to the Clients Model.
Here is how my Client model looks like
[Table("clients")]
public class Client
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string status { get; set; }
public DateTime created_at { get; set; }
public DateTime? modified_at { get; set; }
public Client()
{
status = "Active";
created_at = DateTime.UtcNow;
}
}
Then here is how I am creating a belong to relation using other models.
[Table("BaseClientsToUsers")]
public class ClientToUser : ModelDefault
{
[ForeignKey("User")]
public int UserID { get; set; }
[ForeignKey("Client")]
public int ClientId { get; set; }
[ForeignKey("Team")]
public int DefaultTeamId { get; set; }
public DateTime? JoinedAt { get; set; }
public bool IsActive { get; set; }
public virtual User User { get; set; }
public virtual Client Client { get; set; }
public virtual Team Team { get; set; }
public ClientToUser()
{
DateTime UtcNow = DateTime.UtcNow;
IsActive = true;
CreatedAt = UtcNow;
LastUpdatedAt = UtcNow;
}
[Table("BaseTeams")]
public class Team : ModelDefault
{
[MaxLength(250)]
public string Name { get; set; }
[ForeignKey("Client")]
public int ClientId { get; set; }
public bool IsActive { get; set; }
public virtual Client Client { get; set; }
public Team()
{
DateTime UtcNow = DateTime.UtcNow;
IsActive = true;
CreatedAt = UtcNow;
LastUpdatedAt = UtcNow;
}
}
But, when I try to update my databases I get the following error
Introducing FOREIGN KEY constraint
'FK_dbo.BaseTeams_dbo.BaseClients_ClientId' on table 'BaseTeams' may
cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or
ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could
not create constraint or index. See previous errors.
I am not really sure what could be causing the error but it seems it is because I am creating multiple Foreign keys to the same `Clients model.
How can I fix this error?
Hello #Mike A When I started MVC I got this error too, so you need aditional tables that connects your DB items.
So try connect your database items with tables like that:
Here is my working example:
[Table("Products")]
public class Product
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public decimal InternalPrice { get; set; }
public string Url { get; set; }
}
[Table("Categories")]
public class Category
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public string Url { get; set; }
}
[Table("ProductCategories")]
public class ProductCategory
{
[Key]
[Column(Order = 0)]
public string ProductId { get; set; }
[Key]
[Column(Order = 1)]
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
So you can connect your items without problems hope this will help you.
I am doing a code first example, and basically I have Products and Categories.
The Category Model is as follows :
public class Category
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
and the Product model is as follows:
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public decimal Price { get; set; }
[Required]
public int Stock { get; set; }
public string ImageName { get; set; }
//Category Navigation
public int CategoryId { get; set; }
public Category Category { get; set; }
}
When I try to create a Controller with the Web API 2 Controller with actions, using Entity Framework scaffold, I am getting an error :
There was an error running the selected code generator : 'Key already
exists in table'
I am suspecting its the Category Navigation part of the Product Model since without that code, the scaffold works.
What am I doing wrong? I tried to create it as a virtual property but I am still getting the same error.
You need to add the Model classes in your DbContext
public DbSet<Product> Products{ get; set; }
public DbSet<Category> Categories{ get; set; }
Now you could do the scaffolding.
This question will also help for a better understanding
I have 3 classes for rules,requests,executions, and approvers.
I want to combine these three tables into a viewModel so that I can fetch Requestid, description,approvers and execution status in one single view.
Here is my first crude try which seems to work but I feel this is very incorrect way of creating a ViewModel. Please suggest a better approach.
public class Rules
{
[Required]
public virtual int RulesId { get; set; }
[Required]
public virtual string RulesDescription { get; set; }
[Required]
public virtual int ApprovalLevels { get; set; } //if 0 then auto approved.
[Required]
public virtual string Requestor { get; set; }
}
public class Requests
{
[Required]
public virtual int RequestsId { get; set; }
[Required]
public virtual DateTime RequestTime { get; set; }
[Required]
public virtual bool isCompleted { get; set; }
[Required]
public virtual string UserName { get; set; }
[Required]
public virtual int RulesId { get; set; }
public virtual string Description { get; set; }
}
public class ExecutionStatus
{
[Required]
public virtual int ExecutionStatusId { get; set; }
[Required]
public virtual int RequestId { get; set; }
[Required]
public virtual int CurrentApproverLevel { get; set; }
[Required]
public virtual string ApprovalStatus { get; set; }
}
public class Approvals
{
[Required]
public virtual int ApprovalsId { get; set; }
[Required]
public virtual int RulesId { get; set; }
[Required]
public virtual int ApproverLevel { get; set; }
[Required]
public virtual string ApproverName { get; set; }
}
public class RequestExecutionViewModel
{
private RequestsContext db = new RequestsContext();
public RequestExecutionViewModel(string username)
{
this.Request = db.Requests.Where(a => a.UserName.Equals(username)).First();
//aa = db.Approvals.Where(a => a.RulesId.Equals(Request.RulesId));
this.Approvals = (List<Approvals>) db.Approvals.Where(a => a.RulesId.Equals(Request.RulesId)).ToList();
this.ExecutionStatus = (List<ExecutionStatus>)db.ExecutionStatus.Where(a => a.RequestId.Equals(Request.RequestsId)).ToList();
}
[Required]
public virtual int RequestExecutionViewModelId { get; set; }
public Requests Request {get;set;}
public List<Approvals> Approvals { get; set; }
public List<ExecutionStatus> ExecutionStatus { get; set; }
}
Edit: Doing the database query inside model seems wrong to me. There should be a better way of doing things.
the composition is fairly good, however, you shouldn't have private RequestsContext db = new RequestsContext(); and RequestExecutionViewModel() included in the viewmodel. also, you might want to use IList<> rather than List<>.
your db access should be performed in the service layer or the controller action and should probably be injected via some IOC container.
just my 2 cents
Typically you would do your model building in your Controller Action, not in the ViewModel code itself. Boilerplate mapping code though could be useful in the ViewModel, but the querying of the database I don't think should be in there.
Not all pages will have ViewModels necessarily, and it would lead to DB queries scattered around if some do queries in the controller while some do it in the ViewModel.
In my opinion this seems to be mostly fine. As far as I understand, a ViewModel should be used to provide just enough data from the Model(s) to your View, which yours does.
The only other thing I could suggest is maybe using the Repository pattern instead of directly using a RequestsContext so you could do unit testing better.
I just started playing around with the CTP4 and Code-First. I have the following setup for a possible dating site:
public class User
{
[Key]
public int Id { get; set; }
[Required]
public string LoginName { get; set; }
[Required]
public string Firstname { get; set; }
[Required]
public string Lastname { get; set; }
public string Street { get; set; }
[Required]
public string Zip { get; set; }
[Required]
public string City { get; set; }
[Required]
public bool Gender { get; set; }
[Required]
public int SoughtGender { get; set; }
[Required]
public string Password { get; set; }
[Required]
public double Latitude { get; set; }
[Required]
public double Longitude { get; set; }
}
public class Vote
{
[Key]
public int ID { get; set; }
[Required]
public User Voter { get; set; }
[Required]
public User TargetUser { get; set; }
[Required]
public int Decision { get; set; }
[Required]
public DateTime Timestamp { get; set; }
}
public class MySQLContext : DbContext
{
public MySQLContext (string constring)
: base(constring)
{ }
public DbSet<User> Users { get; set; }
public DbSet<Vote> Votes { get; set; }
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
modelBuilder.Entity<Vote>().HasRequired(b => b.Voter).WithMany();
modelBuilder.Entity<Vote>().HasRequired(b => b.TargetUser).WithMany();
base.OnModelCreating(modelBuilder);
}
}
Now the framework does a nice job of creating the DB with all the proper keys. Now I inserted some dummy data and fired up the following query:
public override IEnumerable<Domain.Vote> FindVotes(Domain.User user)
{
var query = from v in context.Votes where v.Voter.Id == user.Id select v;
return from v in query.AsEnumerable() select v;
}
The query does return the proper Vote entities but the two User properties of the Vote object are Null. Shouldnt the framework populate those properties with the foreign keys of the users referenced in the Vote table?
Let me give you some background on EF so you can understand how this works. EF from day 1 only supported explicit load like one below
Customer.Orders.Load();
Hmm, the feedback was not welcomed by the community and developers wanted lazy loading. To support Lazy Loading EF team said you must mark your navigation property as virtual. So at runtime, Ef creates a proxy object that derives from your entity and overrides the virtual property. Below is an example of such code.
public class Customer
{
public string Name{get;set;}
public virtual ICollection<Order> Orders{get;set;}
}
At runtime there is a proxy that implements IEntityWithChangeTracker and concrete type of the collection is an entitycollection which has been around since version 1.
public class CustomerProxy:Customer,IEntityWithChangeTracker
{
private ICollection<Order> orders;
public override ICollection<Order> Orders
{
if(orders == null)
{
orders = new EntityCollection<Order>();
orders.Load();
}
return orders;
}
}
change your class to the follow
public class Vote {
[Key]
public int ID { get; set; }
[Required]
public virtual User Voter { get; set; }
[Required]
public virtual User TargetUser { get; set; }
[Required]
public int Decision { get; set; }
[Required]
public DateTime Timestamp { get; set; }
}
Notice I've added virtual to the Voter && TargetUser properties and you should be good to go.