I have a custom model like this:
public class VoteOptionModel
{
public List<int> Index { get; set; }
public List<string> Description { get; set; }
}
And i have a method returns me a datatable.I want to bind database values to my custom model.
var filed1= dt.AsEnumerable().Select(s => s.Field<int>("field1")).ToList();
var field2= dt.AsEnumerable().Select(s => s.Field<string("field2")).ToList();
VoteOptionModel model= new VoteOptionModel();
model.Index = visindex;
model.Description = description;
That code is ok but i'm wondering if there is a "better" way. Can we use AsEnumarable() method?
dt.AsEnumarable().Select(r=>new VoteOptionModel{Index=r["filed1"].toList()}); or sth.
You can gather all aggregated data in one run (make sure you initialize lists in model constructor) with Enumerable.Aggregate:
var model = dt.AsEnumerable().Aggregate(new VoteOptionModel(),
(model,r) => {
model.Index.Add(r.Field<int>("field1"));
model.Description.Add(r.Field<string>("field2"));
return model;
});
If you don't want to change model's constructor, then initialize model this way:
new VoteOptionModel() {
Index = new List<int>(),
Description = new List<string>()
}
But I would suggest to have list of models instead of aggregated model, thus you have pairs of index and description values which are strongly related to each other:
public class VoteOptionModel
{
public int Index { get; set; }
public string Description { get; set; }
}
And getting them this way:
var models = dt.AsEnumerable().Select(r => new VoteOptionModel {
Index = r.Field<int>("field1"),
Description = r.Field<string>("field2")
}).ToList();
Related
I have view model class
public class IndexViewModel
{
public int ListOneId { get; set; }
public List<SelectListItem> ListOne { get; set; }
public int ListTwoId {get; set; }
public List<SelectListItem> ListTwo { get; set; }
public int ListThreeId {get; set; }
public List<SelectListItem> ListThree { get; set; }
public int ListFourId {get; set; }
public List<SelectListItem> ListFour { get; set; }
// ...
}
I can populate the view model in the controller class
[HttpGet]
public IActionResult Index()
{
var model = new IndexViewModel();
model.ListOne = _context.ListOne
.Select(x => new SelectListItem() { Text = x.Text, Value = x.Value })
.ToList()
// ...
return View(model);
}
But because the view model populating appears in multiple places, I would like to encapsulate it into its own class.
The question is, what is the suitable name for such a class?
It's not a builder, it's not a factory. Is it seeder, populator or helper? What common suffix can be used here?
Or should it be part of the ViewModel itself (for example with a method that has DbContext as an parameter)?
Update
The question is not about how to name the SelectList Provider but instead where to populate the view model (which class to call this SelectList provider from, whether it's repository, factory, DbContext or else) to minimize duplicates.
To be honest if you add a factory method then it easily becomes a factory pattern. That's what I would do personally
public static List<SelectListItem> GetTheList(int id) =>
id switch
{
1 => ListOne,
2 => ListTwo
//...
_ => throw new Exception("Please select a valid list")
};
//use it like:
List<SelectListItem> list = IndexSelectListFactory.GetTheList(1); //gets ListOne
Notice I have named it IndexSelectListFactory here, just add the suffix that matches the pattern you end up choosing, in this case "-Factory"
But if you do not want to do this, then just keep it simple like "IndexSelectLists"
I need the possiblity to create Code in C# like this
public class SummaryA
{
public string name { get; set; }
public string surename { get: set; }
public int age { get; set;}
}
now I create an list object from the class SummaryA
List<SummaryA> list1= new List<SummaryA>();
yet I need the possibility to remove the column age from the list Summary, anyone have ideas?
I need this for some more columns, so I wish the list was dynamically or some things else.
sry for my bad english.
To completely remove the column you really need another class to store the data in, for example:
public class AgelessSummaryA
{
public string name { get; set; }
public string surename { get: set; }
}
And now you can project the first list into a new list of this class with Linq and Select:
List<AgelessSummaryA> agelessSummaries = ageSummaries
.Select(s => new AgelessSummaryA
{
name = s.name,
surename = s.surename
})
.ToList();
To use it for in a grid or for some display i guess, then you can use anonymous types where you can shape the data the way you like:
var projectedList = (from l in list1
select new
{
name = l.name,
surename = l.surename
}).ToList();
I have run into a caveat with regards to my approach to ASP.NET MVC and viewmodels. Essentially what I do is build a viewmodel in controller/action which merges models together and then passes it to the view.
[HttpGet]
public ActionResult MyAction1()
{
List<StaffModel> staffList = new List<StaffModel>();
var qryStaff = context.Staff.Select(c => new { c.ID, c.name});
foreach (var item in qryStaff )
{
StaffModel myStaffViewModel = new StaffModel
{
ID = item.ID, Name = item.Name
};
staffList.Add(myStaffViewModel );
}
So I do the above process and also do it with employees, exactly the same and then put it into employeeList. I then create my viewModel as the view.
EmployeeStaffViewModel viewModel = new EmployeeStaffViewModel
{
Staff = staffList,
Employee = employeeList
};
I then return the view. I have used employee & staff as an example. I actually have more models I add to the viewModel EmployeeStaffViewModel . It's getting quite big all within the controller action. Should I be creating a ViewModel as a class and then instantiating it in my controller so all the linq and foreach goes in the Model. Therefore I can use it in another controller action.
Thank you for any advice. Will be greatly received.
Lets say you have 3 classes in your ~/Models folder
StaffModel.cs
public class StaffModel
{
public int ID { get; set; }
public string Name { get; set; }
public static Func<Staff, StaffModel> Project = item => new StaffModel
{
ID = item.ID,
Name = item.Name
};
}
EmployeeModel.cs
public class EmployeeModel
{
public int ID { get; set; }
public string Name { get; set; }
public static Func<Employee, EmployeeModel> Project = item => new EmployeeModel
{
ID = item.ID,
Name = item.Name
};
}
EmployeeStaffViewModel.cs
public class EmployeeStaffViewModel
{
public EmployeeStaffViewModel()
{
Staff = new List<StaffModel>();
Employee = new List<EmployeeModel>();
}
public List<StaffModel> Staff { get; set; }
public List<EmployeeModel> Employee { get; set; }
}
The StaffModel and EmployeeModel both have a static Func<> that will map your db entity to your models. These Funcs can be used in your linq queries and expressions which you'll see below.
Your controller action is where you will retrieve your entities from your context. You can simplify your code to not have as many lines as you do.
MyController.cs
[HttpGet]
public ActionResult MyAction1()
{
var model = new EmployeeStaffViewModel();
model.Staff = context.Staff.Select(StaffModel.Project); //Select Staff to StaffModel List
model.Employee = context.Employee.Select(EmployeeModel.Project); //Select Employee to EmployeeModel List
return View(model);
}
I’ve searched for this for a number of hours, but can’t find what I’m looking for answer wise. I have the following:
(Repository.cs)
public class AppRespository
{
private DataContext db = new DataContext();
public IEnumerable<SelectListItem> LoadStates()
{
var query = from d in db.States.ToList()
select new SelectListItem
{
Value = d.StateID.ToString(),
Text = d.State.ToString()
};
return query;
}
}
DataContext.cs
public class DataContext : DbContext
{
public DbSet<States> States { get; set; }
}
ViewModel (States.cs)
public class States
{
[Key]
public int StateID { get; set; }
public IEnumerable<SelectListItem> State { get; set; }
}
Controller (ApplicantController.cs)
// GET: /Applicant/
public ActionResult Index()
{
AppRespository repo = new AppRespository();
States viewModel = new States();
viewModel.State = repo.LoadStates();
return View(viewModel);
}
View:
#Html.DropDownListFor(model=>model.StateID, Model.State, "select")
Why is it when debugging my application I get a null on this line from my repository class?
Text = d.State.ToString(),
State is always null, while StateID is always getting set. I have successfully loaded this drop down before using just my model and controller, but I like this pattern. I'm intermediate w/ ASP MVC so I'm probably missing something.
Any help is appreciated.
Looks like you need to move things around a bit here. I'm making some assumptions about what you want to achieve, but
(Repository.cs)
public class AppRespository
{
private DataContext db = new DataContext();
public IEnumerable<SelectListItem> LoadStates()
{
var query = from d in db.States.ToList()
select new SelectListItem
{
Value = d.StateID.ToString(),
Text = d.State
};
return query;
}
}
DbContext
public class DataContext : DbContext
{
public DbSet<StateEntity> States { get; set; }
}
State Entity
public class StateEntity
{
[Key]
public int StateID { get; set; }
public string State { get; set; }
}
ViewModel
public class StateModel
{
public IEnumerable<SelectListItem> States {get; set;}
}
Controller Action
// GET: /Applicant/
public ActionResult Index()
{
AppRespository repo = new AppRespository();
StateModel viewModel = new StateModel();
viewModel.States = repo.LoadStates();
return View(viewModel);
}
Hopefully this helps get you most of the way there. I'm assuming you want to just load a list of int / string pairs with the StateEntity
Try this
#Html.DropDownListFor(n => n.StateID,
new SelectList(State, "Value", "Text"))
Try changing your query. Instead of:
public IEnumerable<SelectListItem> LoadStates()
{
var query = from d in db.States.ToList()
select new SelectListItem
{
Value = d.StateID.ToString(),
Text = d.State.ToString()
};
return query;
}
Have this:
public IEnumerable<SelectListItem> LoadStates()
{
var query = from d in db.States
select new
{
StateID = d.StateID,
State = d.State
};
var result = from q in query.ToList()
select new SelectedListItem
{
Value = d.StateID.ToString(),
Text = d.State.ToString()
}
return result;
}
The first part of the query sets up a query to get the data from the database the way it's stored there. It uses an anonymous class with 2 properties: StateID and State.
Once the query is ready, we call query.ToList(), which actually runs the query and gets the data, and then makes a list of our anonymous class objects.
Now we can select from the list and convert the data from the anonymous objects to SelectedListItem using .ToString() or any other .NET method.
How to assign a anonymous type to a model?
Using ViewBag I could easily assign like that:
ViewBag.certType = comboType.ToList();
I am removing all ViewBags from my system and now I am trying like that:
model.storeLocations = comboType.ToList();
I am getting the following error:
Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>'
to 'int' S:\Projects\tgpwebged\tgpwebged\Controllers\AdminController.cs
376 40 tgpwebged
Model:
public class TipoDocumentoModel
{
public sistema_DocType Type { get; set; }
public IEnumerable<string> Indices { get; set; }
public IEnumerable<string> NonAssoIndices { get; set; }
public int storeLocations { get; set; }
}
controller:
public ActionResult AdminSettingAddTipo()
{
SettingsModels.TipoDocumentoModel model = new SettingsModels.TipoDocumentoModel();
//Pega os indices e locais de armazenamentos cadastrados no sistema
using (tgpwebgedEntities context = new tgpwebgedEntities())
{
var obj = from u in context.sistema_Indexes select u.idName;
model.Indices = obj.ToList();
var comboType = from c in context.sistema_Armazenamento
select new
{
id = c.id,
local = c.caminhoRepositorio
};
model.storeLocations = comboType.ToList();
}
return PartialView(model);
}
First problem is you are trying to assign a List<> of items to an int property.
Easy way extract out a named class from the anonymous projection.
//model
public List<MyClass> storeLocations { get; set; }
//snip
var comboType = from c in context.sistema_Armazenamento
select new MyClass
{
id = c.id,
local = c.caminhoRepositorio
};
storeLocations = comboType.ToList();
Other Options
If you still want the dynamic behavior you could change your property to be dynamic
Project into a Tuple<int, string>() (guessing on second type)
If the end result is a drop down list you could project into a SelectList()