I have these models
public class employee
{
public int Empid {get;set;}
public string name {get;set;}
public string fname{get;set;}
}
public class empLanguage
{
public string language { get; set; }
public string speaking{ get; set; }
}
public class EmpInsertion
{
public string name { get; set; }
public string fname { get; set; }
public List<ViewModels.Employee.empLanguage> EmpLangs { get; set; }
}
and i have this controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Insert(EmpInsertion empins)
{
if (ModelState.IsValid)
{
Employee Emp = new Employee();
Emp.name= empins.name;
Emp.fname= empins.fname;
var MaxID = (from emp in db.Employees select emp.EmployeeID).Max();
EmpLanguage objlng = new EmpLanguage();
objlng.EmployeeID = MaxID;
foreach (var emplang in Emp.EmpLanguages.ToList())
{
empLanguage lng = new empLanguage();
emplang.Language = lng.language;
emplang.Speaking = lng.speaking;
empins.EmpLangs.Add(lng);
}
}
}
I have two tables Employee(id, name, fname) Language(id, language, speaking, empid) it has one to many relationship, each employee can speak multiple language at same time.
I want to add data in both tables from one view, how can I add to one employee multiple language
I think you can do something like this.
public Employee CreatePartnerWithUser(Employee employee, List<Language> language)
{
using (DataContext context = new DataContext())
{
using (var trans = context.Database.BeginTransaction())
{
var insertEmployee = context.Employee.Add(employee);
context.SaveChanges();
var insertLanguage = context.Language.AddRange(language);
context.SaveChanges();
trans.Commit();
}
}
}
If use DbContext and EF change your model like this:
public class employee
{
public int id {get; set;}
public string name {get; set;}
public string fname {get; set;}
public virtual ICollection<language> language { get; set; }
}
public class language
{
public int id {get; set;}
public string languageName {get; set;}
public virtual ICollection<employee> employee { get; set; }
}
then in DbContext class add this modelBuilder to have many to many relations
modelBuilder.Entity<employee>()
.HasMany(e => e.language)
.WithMany(e => e.employee)
.Map(m => m.ToTable("employeeLanguage").MapLeftKey("employeeID").MapRightKey("languageID"));
after that, you can insert employee in a model like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Insert(employee emp, string langs)
{
if (ModelState.IsValid)
{
using(DbContext db = new DbContext())
{
if(langs != null)
{
string[] strLangs = langs.Split('-');
foreach (var l in strLangs)
{
string lan = l.Trim();
while (lan.Contains(" "))
lan.Replace(" ", " ");
emp.language.Add(new language
{
languageName = lan
});
}
}
db.employee.Add(emp);
db.SaveChanges();
return View("YourReturnPage");
}
}
return View(Insert);
}
and in Insert.cshtml file adds this piece of code:
<div class="form-group">
<label for="Title" class="control-label col-md-2">Languages</label>
<div class="col-md-10">
<textarea type="text" name="langs" class="form-control" value="#ViewBag.langs"></textarea>
<p class="help-block text-danger">Separate language keywords with - </p>
</div>
</div>
Related
I'm trying to build a form for information about upcoming exams. My plan is to make a dropdown list which shows a List of teachers to chose from and who will be responsible for the exam.
Here's a simplified version of my Models:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
public class Teacher
{
public int Id { get; set; }
public int PersonId { get; set; }
public Person Person { get; set; }
}
public class Exam
{
public int Id { get; set; }
public string Subject { get; set; }
public DateTime ExamDate { get; set; }
public int TeacherId { get; set; }
public Teacher Teacher { get; set; }
}
My ViewModel:
public class ExamViewModel
{
public Exam Exam { get; set; }
public IEnumerable<Person> People { get; set; }
public IEnumerable<Teacher> Teachers { get; set; }
}
And my Create action from ExamController:
public ActionResult Create()
{
var people = _context.People.ToList();
var teachers = _context.Teachers.ToList();
var viewModel = new ExamViewModel
{
People = people,
Teachers = teachers,
};
return View(viewModel);
}
I'd like to display People.Firstname + " " + People.Surname of all teachers on the dropdown mentioned above, but instead of submitting People.Id I'd like to submit Teachers.Id to Exams.TeacherId
I first tried to displaying a list of the all FirstName before trying displaying FirstName and Surname with the following razor html helper in my Create view but I already failed there as I was only able to access the properties from one single class (Teachers) to use is as dataValueField and dataTextField for new SelectList():
<h2>Plan exam</h2>
#using (Html.BeginForm("Create", "ExamController"))
{
<div class="form-floating mb-3">
#Html.DropDownListFor(m => m.Exam.TeacherId, new SelectList(Model.Teachers, "Id", "FirstName"), "-- Please select --", new { #class = "form-control", #placeholder = "Teacher" })
#Html.LabelFor(m => m.Exam.TeacherId)
</div>
}
I'm quite new to programming so I'd be very very grateful for any kind of help.
in your viewModel you can only send Exams , but in the query to fetch exams you must make a join to fetch for every exam the teacherID , teacherName , teacherSubname,
to Learn about that check this :
here
or this :
here
another thing , in your model ( classes ) definition , i think you have to add a relationship between Exam and Teacher , and between Teacher an People , if you do so it will be easier to fetch only the necessary data , and you will use only one property ( exams ) in your viewModel to send data to the view, to do so check this here
I found a solution:
First I created a second ViewModel with a property Id for Teacher.Id and FullName for Person.FirstName + " " + Person.Surname:
public class TeacherViewModel
{
public int Id { get; set; }
public string FullName { get ; set; }
}
Then I removed the unnecessary IEnumerable<Person> People from my ExamViewModel and added an IEnumerable<> for Teachers of Type TeacherViewModel:
public class ExamViewModel
{
public Exam Exam { get; set; }
public IEnumerable<TeacherViewModel> Teachers { get; set; }
}
I created a join as mentionen at step 1, converted it to a list in the new TeacherViewModel:
public ActionResult Create()
{
var teachers = (from t in _context.Teachers
join p in _context.People
on t.PersonId equals p.Id
select new TeacherViewModel
{
Id = t.Id,
FullName = p.FirstName + " " + p.Surname,
}).ToList();
var viewModel = new ExamViewModel
{
Teachers = teachers,
};
return View(viewModel);
}
I added a Save() method to the controller:
public ActionResult Save(Exams exam)
{
_context.Exams.Add(exam);
_context.SaveChanges();
return RedirectToAction("Create", "Exams");
}
Added the submit button to the View and changed the action name beside Html.BeginForm( to Save as it will handle saving the variables from the form.
#using (Html.BeginForm("Save", "Exams"))
{
<div class="form-floating mb-3">
#Html.DropDownListFor(m => m.Exam.TeacherId, new SelectList(Model.Teachers, "Id", "FullName"), "-- please select --", new { #class = "form-control", #placeholder = "Teacher" })
#Html.LabelFor(m => m.Exam.TeacherId)
</div>
<button type="submit" class="btn btn-primary">Submit</button>
}
I want to be able to have list for my model which in Create view could be edited. It would be one to many relation. For example:
If I had Client model with possibility of creating shopping list for this person, but list would has it's properties too :
public class Client
{
public int ClientID {get; set}
public string Name {get; set;}
public virtual ICollection<Product> Product {get; set;}
}
public class Product
{
public int ProductID {get; set;}
public int ClientID {get; set;}
public string ProductName {get; set;}
public string Description {get; set;}
public virtual Client Client {get; set;}
}
In create view for Client I want to give him name and be able to add products without any limit and after I would have Client with list of products - save him.
And of course then I want to be able to view Client with list of products in Details view.
What would be the best approach for this? Please advise :)
The best approach is the entity framework and the codefirst method, which I introduced in the example below.
Only I made a small change in the Client class and changed the Product to Products.
public class Client
{
public Client()
{
Products = new List<Product>();
}
public string Name {get; set;}
public virtual ICollection<Product> Products {get; set;}
}
Add Data In DataBase
Client client = new Client();
client.Name = "Client 1";
Product product1 = new Product() { Description = "desc 1", ProductName = "product 1" };
Product product2 = new Product() { Description = "desc 2", ProductName = "product 2" };
Product product3 = new Product() { Description = "desc 3", ProductName = "product 3" };
client.Products.Add(product1);
client.Products.Add(product2);
client.Products.Add(product3);
db.Clients.Add(client);
db.SaveChanges();
Real Example
Just me in this example add the data to the controller in the database which you have to do in the Repository layer.
Your Model
public class Client
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
public virtual Client Client { get; set; }
}
Tour Context
class yourContextName : DbContext
{
public yourContextName() : base("yourConnectionName")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Client>().Property(c => c.ID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Product>().Property(c => c.ID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
public DbSet<Client> Clients
{
get;
set;
}
public DbSet<Product> Products
{
get;
set;
}
}
Your Controller
[HttpGet]
public ActionResult AddProduct()
{
var client = new Client();
client.Name = "Client 1";
return View(client);
}
[HttpPost]
public ActionResult AddProduct(Client client, string[] ProductNames, string[] Descriptions)
{
client.Products = new List<Product>();
for(int i=0;i<ProductNames.Length;i++)
{
if(!string.IsNullOrEmpty(ProductNames[i]))
{
Product product = new Product() { Description =
Descriptions[i], ProductName = ProductNames[i] };
client.Products.Add(product);
}
}
//add data to database
db.Clients.Add(client);
db.SaveChanges();
return View(client);
}
Your View
#model StackOverFlowMVC.Controllers.Client
#{
ViewBag.Title = "AddProduct";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>AddProduct</h2>
#using (Html.BeginForm("AddProduct", "Home", FormMethod.Post, new { id = "myform" }))
{
<label>Client Name : </label>
#Html.TextBoxFor(model => model.Name)
<br />
<hr />
<br />
<div id="prItems">
<section id="row1" num="1">
<div style="margin:10px;">
<label>Product Name 1 : </label>
#Html.TextBox("ProductNames",null)
</div>
<div style="margin:10px;">
<label>Product Descr 1 : </label>
#Html.TextBox("Descriptions", null)
</div>
<input type="button" class="RowDelete" value="-" onclick="removeRow(1)" />
<hr />
</section>
</div>
<button id="btnAddRow">Add Product</button>
<input type="submit" value="submit" id="btnsubmit" />
}
#section scripts{
<script>
$(document).ready(function () {
$('#ProductNames').val('');
$('#Descriptions').val('');
});
$('#btnAddRow').click(function (e) {
e.preventDefault();
var row = "<section><div style = 'margin:10px;'><label></label><input type='text'></div><div style='margin:10px;'><label></label><input type='text'></div><input type='button' class='RowDelete' value='-'/><hr /></section>";
$('#prItems').append(row);
orderRow();
})
function removeRow(num) {
$('#prItems section').each(function (idx) {
if ($(this).attr('num') == num) {
$(this).remove();
}
});
orderRow();
}
function orderRow() {
var rowCount = $('#prItems section').length;
if (rowCount > 0) {
$('#prItems section').each(function (idx) {
var num = idx + 1;
$(this).attr('id', 'row' + num);
$(this).attr('num', num);
$(this).children().children().nextAll().slice(0, 1).prev().text('Product Name ' + num + " : ");
$(this).children().children().nextAll().slice(0, 1).attr('name', 'ProductNames');
$(this).children().next().children().nextAll().slice(0, 1).prev().text('Product Descr ' + num + " : ");
$(this).children().next().children().nextAll().slice(0, 1).attr('name', 'Descriptions');
$(this).children().next().next().slice(0, 1).attr('onclick', 'removeRow(' + num + ')');
});
}
}
</script>
}
I have a form which has a place where a user can insert multiple tags separated by a comma into the database. I got it to insert, but I'm having trouble retrieving it to show on my edit form.
This is my Edit Action:
public IActionResult Edit(int id)
{
var gallery = _ctx.GalleryImages.SingleOrDefault(m => m.Id == id);
if (gallery == null)
return NotFound();
var categories = _ctx.Categories.ToList();
var model = new GalleryFormViewModel(gallery)
{
Tags = gallery.Tags,
Category = categories,
};
return View("Views/Image/UploadForm.cshtml", model);
}
Here is my ViewModel:
public class GalleryFormViewModel
{
public int? Id { get; set; }
public string Title { get; set; }
public IEnumerable<ImageTag> Tags { get; set; }
public IEnumerable<Category> Category { get; set; }
[Required]
public int CategoryId { get; set; }
public IFormFile ImageUplaod { get; set; }
public GalleryFormViewModel()
{
Id = 0;
}
public GalleryFormViewModel(GalleryImage galleryImage)
{
Id = galleryImage.Id;
Title = galleryImage.Title;
Tags = galleryImage.Tags;
CategoryId = galleryImage.CategoryId;
}
}
And here is the Form input: (I'm using this form for creating and editing the gallery)
<div class="form-group">
#Html.LabelFor(m => m.Tags)
#Html.TextBoxFor(m => m.Tags, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Tags)
</div>
Here is the Tag Model:
namespace SimpleImageGallery.Data.Models
{
public class ImageTag
{
public int Id { get; set; }
public string Description { get; set; }
}
}
Here is the Gallery Model:
public class GalleryImage
{
public virtual IEnumerable<ImageTag> Tags { get; set; }
// ....
}
This is how the tags table looks in the database:
It seems like I'm not getting any errors, maybe something is wrong in the actual input field?
There are some mistakes :
First, you have to Include the Tags to retrieve them from DB (if using Entity Framework):
var gallery = _ctx.GalleryImages.Include(m=>m.Tags).SingleOrDefault(m => m.Id == id);
Secondly, you are doing the same this twice :
var model = new GalleryFormViewModel(gallery)
{
Tags = gallery.Tags,
Category = categories,
};
and
public GalleryFormViewModel(GalleryImage galleryImage)
{
Id = galleryImage.Id;
Title = galleryImage.Title;
Tags = galleryImage.Tags;
CategoryId = galleryImage.CategoryId;
}
Thirdly, you cannot do this : #Html.TextBoxFor(m => m.Tags, new { #class = "form-control" }) for a enumerable, you have to reconstruct the string.
I'm trying to get values from userList viewbag.i can't figure out the solution. Error is:
An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code
Additional information: 'object' does not contain a definition for 'name'
though in ViewBag.userList contains data (2 objects) which i can see while debugging
#foreach (var aUser in ViewBag.userList)
{
<tr>
<td>#aUser.name</td>
<td>#aUser.username</td>
.....
<td>#Html.ActionLink("Edit", "UserEdit","Users")</td>
<td>#Html.ActionLink("Delete", "UserDelete", "Users")</td>
</tr>
}
I have a superclass and a childclass
superclass
public partial class user
{
public int id { get; set; }
public string name { get; set; }
public string username { get; set; }
...
public string user_role { get; set; }
}
childclass
public class UserSub: user
{
public string CreatedUserName { get; set; }
public string ModifiedUserName { get; set; }
}
In my controller i used linq to get values from database and stored it to Viewbag.userList. My controller function is
public ActionResult UserList()
{
IEnumerable<user> users = null;
users = dbEntities.users.ToList();
if (users != null)
{
var userLists = (from a in users join b in users on a.created_user_id equals b.id select new { a.name, a.username, a.password, a.user_role, a.is_enable, a.is_approved, CreatedUserName = b.name, a.create_time, a.is_android, a.device_id }).ToList();
ViewBag.userList = userLists;
}
return View();
}
tried List<UserSub> users=ViewBag.userList....getting error too
Use a ViewModel to share data between view and controller.
For example, first create the ViewModel:
public class userViewModel{
public int id { get; set; }
public string name { get; set; }
public string username { get; set; }
public string user_role { get; set; }
public string CreatedUserName { get; set; }
public string ModifiedUserName { get; set; }
...
}
You can put all data that you need in your view model... Then, I'll recommend you create a class in your model with all the queries that you need (you have to investigate how to do), but you can get the queries from your controller (if you want).
Well, edit your controller function:
public ActionResult UserList()
{
List<userViewModel> userVM = new List<userViewModel>(); //Important! Don't return all the query, just the data that you need.
IEnumerable<user> users = null;
users = dbEntities.users.ToList();
if (users != null)
{
var userLists = (from a in users join b in users on a.created_user_id equals b.id select new { a.name, a.username, a.password, a.user_role, a.is_enable, a.is_approved, CreatedUserName = b.name, a.create_time, a.is_android, a.device_id }).ToList(); //I'm going to suppose that your query is ok and you get all the data that you need...
foreach (var item in userLists)
{
userVM.Add(new userVM(){
userVM.name = item.name;
userVM.username = item.username;
userVM.user_role = item.user_role;
.......
});
}
}
return View(userVM); //return your view model
}
Finally, modify your view and call the ViewModel userViewModel
#model Model.ViewModel.userViewModel //It depends on the namespace
//Then try something likes this...
#foreach (var aUser in Model)
{
<tr>
<td>#aUser.name</td>
<td>#aUser.username</td>
.....
<td>#Html.ActionLink("Edit", "UserEdit","Users")</td>
<td>#Html.ActionLink("Delete", "UserDelete", "Users")</td>
</tr>
}
That's the idea, improve my answer. ;)
I'm use bundle of: ASP.NET MVC3, SQL Server 2012, EF5. When I try to save values into my database, I can save only Book's property IsSelected in Books table in my database, StudentName cant saved, and cant saved datas into my StudentBooks table in database, whach contains StudentId and BookId, keys for many-to-many relationships, any ideas?
public class CheckboxController : Controller
{
EFDbContext context = new EFDbContext(ConfigurationManager.ConnectionStrings[1].ConnectionString);
//
//GET: /Checkbox/
public ActionResult Index()
{
ViewModelData vmd = new ViewModelData();
List<Book> bookList = new List<Book>();
using (EFDbContext te = new EFDbContext(ConfigurationManager.ConnectionStrings[1].ConnectionString))
{
var student = te.Students.First();
vmd.StudentName = student.StudentName;
var data = te.Books.ToList();
foreach (var d in data) {
Book book = new Book();
book.BookName = d.BookName;
book.IsSelected = false;
book.BookId = d.BookId;
bookList.Add(book);
}
}
vmd.Books = bookList;
return View(vmd);
}
//
//GET: /Checkbox/
[HttpPost]
public ActionResult Index(ViewModelData vm)
{
foreach (var book in vm.Books) {
context.Books.First(x => x.BookId == book.BookId).IsSelected = book.IsSelected;
}
context.SaveChanges();
return View(vm);
}
}
public class ViewModelData
{
public string StudentName { get; set; }
public List<Book> Books { get; set; }
}
View
#model UsingEFNew.Controllers.ViewModelData
#{
ViewBag.Title = "Example";
}
#using (Html.BeginForm("Index", "Checkbox", null, FormMethod.Post))
{
<div>Your Name:</div>
<div>
#Html.TextBoxFor(model => model.StudentName)
</div>
for (int i = 0; i < Model.Books.Count; i++) {
#Html.CheckBoxFor(m => Model.Books[i].IsSelected)
#Html.DisplayFor(m => Model.Books[i].BookName)
#Html.HiddenFor(m => Model.Books[i].BookId)
#Html.HiddenFor(m => Model.Books[i].BookName)
#:</br>
}
}
My Models
public class Book {
public int BookId { get; set; }
public string BookName { get; set; }
public bool IsSelected { get; set; }
public ICollection<Student> Students { get; set; }
}
public class Student {
public int StudentId { get; set; }
public string StudentName { get; set; }
public ICollection<Book> Books { get; set; }
public ICollection<City> Cities { get; set; }
}
In your [HttpPost]Index you're not take the student Name from you ViewDataModel and pushing it into any Student entity.
[HttpPost]
public ActionResult Index(ViewModelData vm)
{
foreach (var book in vm.Books) {
context.Books.First(x => x.BookId == book.BookId).IsSelected = book.IsSelected;
}
var student = context.Students.First();
student.Name = vm.StudentName;//now I've actually changed the student entity and changes will be pushed to database on Save()
context.SaveChanges();
return View(vm);
}
It doesn't look like you're really leveraging the relationship between them however. You just grab the first student rather than using the relationship from book to student. I have done the same here just to demonstrate mapping the value from your view model into your entity.