Populating SelectLists in viewmodels - asp.net-mvc

I have a legacy table represented by the following model:
public class Employee
{
[Key]
[Column("employee_id")]
public string EmployeeId { get; set; }
[Column("first_name")]
public string FirstName { get; set; }
[Column("last_name")]
public string LastName { get; set; }
[Column("active")]
public bool Active { get; set; }
}
I don't have a viewmodel for this class and it will only be used to populate SelectLists (via repository) in other viewmodels in my app. However, I want to create a property like so, to concatenate the first and last names for the SelectLists/dropdown:
private string _EmployeeName;
public string EmployeeName
{
get
{
return _EmployeeName;
}
set
{
_EmployeeName = this.FirstName + " " + this.LastName;
}
}
When I put the EmployeeName in my Employee model, I get an error that the column EmployeeName doesn't exist. Ok, makes sense because this is my model and their is no such column.
Here is an abbreviated example of one viewmodelthat uses the SelectList:
public class EquipmentViewModel
{
[Display(Name = "Equipment ID:")]
public string EquipmentId { get; set; }
[Required(ErrorMessage = "Equipment name is required.")]
[Display(Name = "Equipment Name:")]
[MaxLength(128)]
public string EquipmentName { get; set; }
public SelectList EmployeeList { get; set; }
}
In my controller, I do this:
var emp = iEmployeeRepository.FindBy(x => x.Active == true).OrderBy(x => x.FirstName);
var equipmentViewModel = new EquipmentViewModel
{
EquipmentId = e.EquipmentId,
EquipmentName = e.EquipmentName,
OriginatorEmployeeId = e.OriginatorEmployeeId,
EmployeeList = new SelectList(emp, "EmployeeId", "FirstName"),
};
return View(equipmentViewModel);
Since I don't have a viewmodel for the Employee class, where can I put this EmployeeName property to replace FirstName? If someone could point me in the right direction I'd be grateful.

You don't need an EmployeeName property. Do this in your controller:
var emp = iEmployeeRepository.FindBy(x => x.Active == true)
.OrderBy(x => x.FirstName)
.Select(x => new { EmployeeId = x.EmployeeId, EmployeeName = x.FristName + " " + x.LastName });
var equipmentViewModel = new EquipmentViewModel
{
EquipmentId = e.EquipmentId,
EquipmentName = e.EquipmentName,
OriginatorEmployeeId = e.OriginatorEmployeeId,
EmployeeList = new SelectList(emp, "EmployeeId", "EmployeeName"),
};
return View(equipmentViewModel);

Related

LINQ Query Parent-Child tables

The problem I'm having goes like this:
I have a textbox in my view that allows search/filter functionality of the Orders table. However, I would like it to be able to also search by the child table OrderDetails and filter appropriately.
The search textbox works for the order table but not the order details.
I realize this code can be shrunk down a lot but I'm new coding.
Something that may help - I'm doing Database first
Here is my code so far.
Controller:
EntitiesDB db = new EntitiesDB();
#region INDEX MAIN PAGE
[HttpGet]
public ActionResult Index(string sortOrder, string currentFilter, int? page, string jobNumberDropDown, string requesitionerDropDown, string supplierDropDown, string dateRequestedDropDown, string dateRequiredDropDown, string searchString)
{
var getSupplierList = db.Suppliers.OrderBy(SL => SL.SupplierName).ToList();
var getEmployeeList = db.Employees.OrderBy(EL => EL.FullName).ToList();
SelectList listOfSuppliers = new SelectList(getSupplierList, "SupplierName", "SupplierName");
SelectList listOfEmployees = new SelectList(getEmployeeList, "FullName", "FullName");
ViewBag.supplierNames = listOfSuppliers;
ViewBag.employeeNames = listOfEmployees;
#region PAGINATION FUNCTION
//Code for Paging
ViewBag.CurrentSort = sortOrder;
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = currentFilter;
int pageSize = 10;
int pageNumber = (page ?? 1);
#endregion
#region SEARCH FUNCTION
//Creates the LINQ Query to select the Orders from the ORDERS table
//var orders = from o in db.Orders join c in db.OrderDetails on o.OrderID equals c.OrderID select new { orders = o.JobNumber, o.PurchaseOrder, c.Description, c.PartNumber, c.AngstromPartNumber };
var orders = from o in db.Orders.Where(x => x.IsDeleted != true) select o; /*-****WORKING FOR ORDER TABLE*****/
var orderDetails = from od in db.OrderDetails.Where(x => x.IsDeleted != true) select od;
//List of Employees
var requesitionerList = new List<string>();
//List of Suppliers
var supplierList = new List<string>();
//List of Job Numbers
var jobNumberList = new List<string>();
//List of Dates Requested
var dateRequestedList = new List<DateTime>();
//List of Dates Required
var dateRequiredList = new List<DateTime>();
//Query the ORDERS table columns
var requesitionerQry = from r in db.Orders.Where(x => x.IsDeleted != true) orderby r.Requesitioner select r.Requesitioner;
var supplierQry = from s in db.Orders.Where(x => x.IsDeleted != true) orderby s.Supplier select s.Supplier;
var jobNumberQry = from j in db.Orders.Where(x => x.IsDeleted != true) orderby j.JobNumber select j.JobNumber;
var dateRequestedQry = from DRqst in db.Orders.Where(x => x.IsDeleted != true) orderby DRqst.DateRequested select DRqst.DateRequested;
var dateRequiredQry = from DRqrd in db.Orders.Where(x => x.IsDeleted != true) orderby DRqrd.DateRequired select DRqrd.DateRequired;
//Searches through the columns filters out NULLS
var t = requesitionerQry.Distinct().ToList().Where(x => String.IsNullOrWhiteSpace(x) == false);
var u = supplierQry.Distinct().ToList().Where(y => String.IsNullOrWhiteSpace(y) == false);
var v = jobNumberQry.Distinct().ToList().Where(z => String.IsNullOrWhiteSpace(z) == false);
var dRT = dateRequestedQry.Distinct().ToList().Where(z1 => String.IsNullOrWhiteSpace(z1.ToString()) == false);
var dRD = dateRequiredQry.Distinct().ToList().Where(z2 => String.IsNullOrWhiteSpace(z2.ToString()) == false);
//Searches through the columns and only pulls out one of each unique string
requesitionerList.AddRange(t);
supplierList.AddRange(u);
jobNumberList.AddRange(v);
dateRequestedList.AddRange(dRT);
dateRequiredList.AddRange(dRD);
//I believe this Grabs the list items and arranges them into a viewable anonamous object
ViewBag.requesitionerDropDown = new SelectList(requesitionerList);
ViewBag.supplierDropDown = new SelectList(supplierList);
ViewBag.jobNumberDropDown = new SelectList(jobNumberList);
ViewBag.dateRequestedDropDown = new SelectList(dateRequestedList);
ViewBag.dateRequiredDropDown = new SelectList(dateRequiredList);
//This defines which columns the text in the search textbox should locate
if (!String.IsNullOrEmpty(searchString))
{
orders = orders.Where(a => a.JobNumber.Contains(searchString)||
//a.Description.Contains(searchString) || a.PartNumber.Contains(searchString) || a.AngstromPartNumber.Contains(searchString) ||
a.Supplier.Contains(searchString) || a.Reason.Contains(searchString) || a.Requesitioner.Contains(searchString) ||
a.DateRequested.ToString().Contains(searchString) || a.DateRequired.ToString().Contains(searchString) ||
a.ExpectedDate.ToString().Contains(searchString) || a.DateOrderPlaced.ToString().Contains(searchString) ||
a.PurchaseOrder.ToString().Contains(searchString));
}
if (!String.IsNullOrEmpty(searchString))
{
orders = orders.Where(x => x.OrderDetails.Any(i => i.Description.Contains(searchString)));
}
//Search the REQUESITIONER column
if (!String.IsNullOrEmpty(requesitionerDropDown))
{
orders = orders.Where(b => b.Requesitioner == requesitionerDropDown);
}
//Search the SUPPLIER column
if (!String.IsNullOrEmpty(supplierDropDown))
{
orders = orders.Where(c => c.Supplier == supplierDropDown);
}
//Search the JOBNUMBER column
if (!String.IsNullOrEmpty(jobNumberDropDown))
{
orders = orders.Where(d => d.JobNumber == jobNumberDropDown);
}
if (!String.IsNullOrEmpty(dateRequestedDropDown))
{
orders = orders.Where(d => d.DateRequested.ToShortDateString() == dateRequestedDropDown);
}
if (!String.IsNullOrEmpty(dateRequiredDropDown))
{
orders = orders.Where(d => d.DateRequired.ToShortDateString() == dateRequiredDropDown);
}
#endregion
//List<Order> OrderList = db.Orders.ToList();
var sortedOrders = orders.OrderBy(x => x.JobNumber);
return View(sortedOrders.ToPagedList(pageNumber, pageSize));
}
#endregion
Here are my Models:
public partial class Order
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Order()
{
this.OrderDetails = new HashSet<OrderDetail>();
}
public System.Guid OrderID { get; set; }
public Nullable<bool> IsDeleted { get; set; }
public string JobNumber { get; set; }
public string Supplier { get; set; }
public string Reason { get; set; }
public string Requesitioner { get; set; }
public System.DateTime DateRequested { get; set; }
public System.DateTime DateRequired { get; set; }
public Nullable<bool> Urgent { get; set; }
public System.DateTime ExpectedDate { get; set; }
public System.DateTime DateOrderPlaced { get; set; }
public string PurchaseOrder { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
}
public partial class OrderDetail
{
public System.Guid OrderDetailID { get; set; }
public Nullable<bool> IsDeleted { get; set; }
public int Quantity { get; set; }
public string Description { get; set; }
public string PartNumber { get; set; }
public string Notes { get; set; }
public string Comments { get; set; }
public Nullable<decimal> UnitPrice { get; set; }
public string AngstromPartNumber { get; set; }
public string Manufacturer { get; set; }
public Nullable<int> BoneYard { get; set; }
public System.Guid OrderID { get; set; }
public Nullable<System.Guid> EmployeeID { get; set; }
public Nullable<System.Guid> SupplierID { get; set; }
public virtual Employee Employee { get; set; }
public virtual Order Order { get; set; }
public virtual Supplier Supplier { get; set; }
}

Add comment - two model in one view

I would like to add two model in one view: CommentVM and BlogVM.
CommentVM - comments,
BlogVM - postDetails.
I try to add comment via ajax to my databse and than pass my two model in to view. But when I try to display my page I received error that my object is null (commentVM)
below code my controller
Any sugestion what I am doing wrong?
Thank for your help!
// GET: Admin/Blog/kategoria/{name}/post/id
[ActionName("post")]
public ActionResult PostDetails(int id)
{
//Declare BlogVM
BlogVM model;
CommentVM model2;
int id2;
using (Db db = new Db())
{
//Get the page
BlogDTO dto = db.Blog.Find(id);
//Confirm page exist
if (dto == null)
{
return Content("Taka strona nie istnieje!");
}
//Init BlogVM
model = new BlogVM(dto);
id2 = dto.Id;
// CommentDTO dto2 = db.Comments.Find(x => x.PostId == id2);
model2 = new CommentVM();
}
var finalItem = new DetailsComment
{
Blog = model,
Comment = model2
};
return View("PostDetails", finalItem);
}
code my models:
public class CommentVM
{
public CommentVM()
{
}
public CommentVM(CommentDTO row)
{
Id = row.Id;
Name = row.Name;
Body = row.Body;
PostId = row.PostId;
CreatedAt = row.CreatedAt;
}
public int Id { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
public string Name { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
public string Body { get; set; }
public int PostId { get; set; }
public DateTime CreatedAt { get; set; }
//public IEnumerable<CommentVM> CommentDetails { get; set; }
}
public class BlogVM
{
public BlogVM()
{
}
public BlogVM(BlogDTO row)
{
Id = row.Id;
Title = row.Title;
Slug = row.Slug;
Body = row.Body;
CategoryName = row.CategoryName;
CategoryId = row.CategoryId;
CreatedAt = row.CreatedAt;
Sorting = row.Sorting;
HasSidebar = row.HasSidebar;
}
public int Id { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
public string Title { get; set; }
public string Slug { get; set; }
[Required]
[StringLength(int.MaxValue, MinimumLength = 3)]
[AllowHtml]
public string Body { get; set; }
public string CategoryName { get; set; }
[Required]
public int CategoryId { get; set; }
public DateTime CreatedAt { get; set; }
public int Sorting { get; set; }
public bool HasSidebar { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
public class DetailsComment
{
public BlogVM Blog { get; set; }
public CommentVM Comment { get; set; }
public IEnumerable<CommentVM> CommentDetails { get; set; }
}
In my view
#foreach (var item in Model.CommentDetails)
{
<tr>
<td>
<div class="ajaxdivtd"></div>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Body)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedAt)
</td>
</tr>
}
If, according to your comments, you have multiple comments per post, then here's what you need to do:
//Declare BlogVM
BlogVM model;
CommentVM model2; //you can probably get rid of this variable since you want multiple comments per post, rather than a single one, but that's up to you
List<CommentVM> commentsModel; //new List object to hold the multiple comments for the post
and:
id2 = dto.Id;
var dto2 = db.Comments.Find(x => x.PostId == id2);
//Convert dto2 from an list/enumerable of CommentDTO to a List<CommentVM>, perhaps via AutoMapper (or other such utility), or even manually via a foreach
commentsModel = YourConversionMethod(dto2);
finally:
var finalItem = new DetailsComment
{
Blog = model,
Comment = model2,
CommentDetails = commentsModel
};

MVC ASP.net Multiple Views trying to store tags

Model:
public class PublishedSongViewModel
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false)]
public string SongName { get; set; }
//...
[Required]
public IEnumerable<string> Category { get; set; }
}
public class CategoryViewModel
{
public short Id { get; set; }
public string Title { get; set; }
public virtual ICollection<SongCategoryViewModel> SongCategory { get; set; }
}
public class SongCategoryViewModel
{
public int Id { get; set; }
[Required]
public int PublishedSongId { get; set; }
[Required]
public short CategoryId { get; set; }
}
View:
#model IList<PublishedSongViewModel>
#using (Html.BeginForm("PublishMusic", "Publish", FormMethod.Post, new { #enctype = "multipart/form-data", #id = "form-upload" }))
{
#Html.DropDownListFor(x => Model[i].Category, new SelectList(//Categories list here), new { #class = "form-control dl_Categories ", Multiple = "Multiple" })
}
Controller:
[HttpPost]
public ActionResult PublishMusic(IEnumerable<PublishedSongViewModel> songDetails)
{
if (songDetails != null)
{
IEnumerable<PublishedSongViewModel> savedSongs = (IEnumerable<PublishedSongViewModel>)(Session["UserSongs"]);
var lookupDetails = songDetails.ToDictionary(song => song.Id, song => song);
if (savedSongs != null)
{
foreach (var publishedSong in savedSongs)
{
var key = publishedSong.Id;
if (lookupDetails.ContainsKey(key))
{
var details = lookupDetails[key];
publishedSong.SongName = details.SongName;
}
db.SongCategories.Add(new SongCategoryViewModel { PublishedSongId = key, CategoryId = //categories id that user typed in on editorFor});
db.PublishedSongs.Add(publishedSong);
db.SaveChanges();
}
}
}
return View("Index");
}
I'v filled CategoryViewModel table up with data in my SQL.
1) How do I get the titles of CategoryViewModel and pass them in the SelectList(//Here) parameter in my viewmodel?
2) In the PublishMusic Action, how do I get the CategoryId for the SongCategoryViewModel from the one or more categories that the user selected from songDetails.Category?
I am not sure if I am on the right track with this. basically the categories are like tags, the user can select more than one. I'v also cut out unessential code to make easier to read.

Unsure how to insert item into database using Entity Framework with many to many relationship

I am trying to insert a product into my database with an associated category. One product can belong to several categories and obviously one category can have several products. When I insert, I am sure I am missing something in my controller method but I'm not sure what it is. I have a bridge table called ProductCategory that just has a ProductID and a CategoryID in it. That table is not getting populated when I do the insert.
Here is my controller method that is doing the insert:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditProduct([Bind(Include = "ID,itemNumber,product,description,active,PDFName,imageName,SelectedCategories")] ProductModel model)
{
if (ModelState.IsValid)
{
using (var context = new ProductContext())
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
if (model.ID == 0)
{
// Since it didn't have a ProductID, we assume this
// is a new Product
if (model.description == null || model.description.Trim() == "")
{
model.description = "Our Famous " + model.product;
}
if (model.imageName == null || model.imageName.Trim() == "")
{
model.imageName = model.itemNumber + ".jpg";
}
if (model.PDFName == null || model.PDFName.Trim() == "")
{
model.PDFName = model.itemNumber + ".pdf";
}
Session["dropdownID"] = model.ID;
// I think I probably need some additional code here...
context.Products.Add(model);
}
else
{
// Since EF doesn't know about this product (it was instantiated by
// the ModelBinder and not EF itself, we need to tell EF that the
// object exists and that it is a modified copy of an existing row
context.Entry(model).State = EntityState.Modified;
}
context.SaveChanges();
return RedirectToAction("ControlPanel");
}
}
return View(model);
}
And my Product model:
public class ProductModel
{
public int ID { get; set; }
[Required(ErrorMessage = "Required")]
[Index("ItemNumber", 1, IsUnique = true)]
[Display(Name = "Item #")]
public int itemNumber { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Product")]
[MaxLength(50)]
public String product { get; set; }
[Display(Name = "Description")]
[MaxLength(500)]
public String description { get; set; }
[DefaultValue(true)]
[Display(Name = "Active?")]
public bool active { get; set; }
[Display(Name = "Image Name")]
public String imageName { get; set; }
[Display(Name = "PDF Name")]
public String PDFName { get; set; }
[Display(Name = "Category(s)")]
public virtual ICollection<CategoryModel> ProductCategories { get; set; }
public int[] SelectedCategories { get; set; }
public IEnumerable<SelectListItem> CategorySelectList { get; set; }
//public ICollection<CategoryModel> CategoryList { get; set; }
public virtual BrochureModel Brochure { get; set; }
public IEnumerable<SelectListItem> BrochureList { get; set; }
[Display(Name = "Category(s)")]
public String CategoryList { get; set; }
public static IEnumerable<SelectListItem> getCategories(int id = 0)
{
using (var db = new ProductContext())
{
List<SelectListItem> list = new List<SelectListItem>();
var categories = db.Categories.ToList();
foreach (var cat in categories)
{
SelectListItem sli = new SelectListItem { Value = cat.ID.ToString(), Text = cat.categoryName };
//if (id > 0 && cat.ID == id)
//{
// sli.Selected = true;
//}
list.Add(sli);
}
return list;
}
}
public ProductModel()
{
active = true;
}
}
And my Category model:
public class CategoryModel
{
public int ID { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Category Name")]
[MaxLength(50)]
public String categoryName { get; set; }
[MaxLength(50)]
public String categoryDBName { get; set; }
[DefaultValue(true)]
[Display(Name = "Active?")]
public bool isActive { get; set; }
//public virtual ICollection<ProductCategory> ProductCategories { get; set; }
public virtual ICollection<ProductModel> Products { get; set; }
}
Here is my Product context:
public class ProductContext : DbContext
{
public ProductContext()
: base("DefaultConnection")
{
Database.SetInitializer<ProductContext>(new CreateDatabaseIfNotExists<ProductContext>());
}
public DbSet<CategoryModel> Categories { get; set; }
public DbSet<ProductModel> Products { get; set; }
public DbSet<BrochureModel> Brochures { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
//modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
modelBuilder.Entity<CategoryModel>().ToTable("Categories");
modelBuilder.Entity<ProductModel>().ToTable("Products");
modelBuilder.Entity<BrochureModel>().ToTable("Brochures");
modelBuilder.Entity<ProductModel>()
.HasMany(p => p.ProductCategories)
.WithMany(p => p.Products)
.Map(m =>
{
m.ToTable("ProductCategory");
m.MapLeftKey("ProductID");
m.MapRightKey("CategoryID");
});
//modelBuilder.Entity<CategoryModel>()
//.HasMany(c => c.ProductCategories)
//.WithRequired()
//.HasForeignKey(c => c.CategoryID);
}
public System.Data.Entity.DbSet<newBestPlay.Models.RegisterViewModel> RegisterViewModels { get; set; }
}
Let me know if other code or more info is needed.
You're never doing anything with your SelectedCategories array. You need to use this to pull CategoryModel instance from the database and then associate those with the product.
context.Categories.Where(c => model.SelectedCategories.Contains(c.ID)).ToList()
.ForEach(c => model.ProductCategories.Add(c));
...
context.SaveChanges();
UPDATE
Can I ask how to list out the categories for each product in my view?
That's kind of a loaded question, as it's highly dependent on what type of experience you're trying to achieve. Generally speaking, with any collection, you'll need to iterate over the items in that collection and then render some bit of HTML for each item. You can do this in a number of different ways, which is why there's not really one "right" answer I can give you. However, just to give you an idea and not leave you with no code at all, here's a very basic way to just list out the name of every category:
#string.Join(", ", Model.ProductCategories.Select(c => c.categoryName))

Expression Func in Selector

I created two selector using Exp-Func I want to execute both in a single query. Code is as follows:
Expression<Func<Scholar, ScholarCultureWatchListView>> selector = z => new ScholarCultureWatchListView
{
ScholarId = z.ID,
Name = z.FirstName + " " + z.LastName
};
Expression<Func<Scholar, ScholarCultureWatchListView>> selector2 = z => new ScholarCultureWatchListView
{
Grade = z.CurrentGrade
};
var result= from s in db.Scholars
select new ScholarCultureWatchListView
{
**?????What is write here (selector, selector2)**
}
public class ScholarCultureWatchListView
{
public long ScholarId { get; set; }
public string Name { get; set; }
public Grade? Grade { get; set; }
public bool? HoldOverSkip { get; set; }
public Grade? GradeHoldOver { get; set; }
public bool? Iep { get; set; }
public int Tardies { get; set; }
public int Absences { get; set; }
public int YtdSuspensions { get; set; }
....
}
please solve my problem.
Thanks
If you want to get two separate instances of ScholarCultureWatchListView returned from a single call, you can do for example this (and you don't need selectors at all):
var result = from s in db.Scholars
select new[]
{
new ScholarCultureWatchListView
{
ScholarId = s.ID,
Name = s.FirstName + " " + z.LastName
},
new ScholarCultureWatchListView
{
Grade = z.CurrentGrade
},
};

Resources