I have a table in the database that is a list of Products. Then I have a Fundraiser class (made into a controller and views) that will have a "collection" of Products. The point is that "for this fundraiser, I am selling these selected products".
My idea is to have a list of checkboxes so that the user can select which products are to be included in the fundraiser. I know that the typical way of doing this is to have an intermediary table that has a compound key of ProductID and FundraiserID. I don't want to do this.
Instead my idea is to make the list of products as checkboxes, use JavaScript to create a JSON string as the user selects/deselects the checkboxes, then save that JSON string into a simple text field in the Fundraiser table.
public class Fundraiser
{
public int FundraiserID { get; set; }
public string EventName { get; set; }
public string ItemsList { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
}
So, there are two ways that I'm thinking this can go.
How do I write raw HTML so that I can manually iterate through the resultset of the Products table and create the checkboxes. Right now, the HTML I write is shown literally on the page instead of interpreted.
ViewData["ProductList"] = "<input type='checkbox' id='prod12' checked>";
// Is escaped or something so that it does not render as an HTML input
OR
Is there an HTML helper or some other tool that will do this through class methods or something (so that I can do it in the 'proper' OOP style)?
ViewData["ProductList"] = new ListOfCheckBoxes(_context.Products, "ProductID"......
I have a background in PHP programming, and I rarely used third-party code, so having all these high-level "helpers" is really confusing for me. I just want to write the code!
Related
I want to accept different model type from body based on query param value.
Example:
[HttpGet]
[Route("GetSystemdetails")]
public string Getdeatils([FromBody] SystemDetail sysdetails, string type)
{
//some code here
string details = getdetails(sysdetails);
}
// abc model
public class abc
{
public int UserID { get; set; }
public string Email { get; set; }
}
//xyz model
public class xyz
{
public int xyzid { get; set; }
public string systemval { get; set; }
public string snum { get; set; }
}
type abc and xyz will have it's own model. So based on type I receive in query param I wanted to pick the model and proceed.
Sample url:
localhost/GetSystemdetails/type=abc
localhost/GetSystemdetails/type=xyz
I thought of creating a new model SystemDetail which holds these two models(xyz and abc) and based on system pick them.
I wanted to know what are possible ways to achieve this kind of requirements without creating multiple methods in controller(I don't want to change the format of the URL).
That's not something that's supported out of the box. Your linked solution is probably the closest you'll get to that.
ASP.NET Core is not supposed to take values of the parameters into account when routing, except for validation.
There are several possible ways to do so
Having multiple model objects
As in the link you provided, you can declare multiple model objects. The site has given the example of
public class PostUserGCM
{
public User User { get; set; }
public GCM GCM { get; set; }
}
but you can use your own examples.
Base model
Your models can inherit from some base model. If you only need a single model at a time and they share some similarities, then you could just create a base model which the other two are inheriting from, be agnostic at implementation time and your use cases will mainly differ on instantiation inside the controller, while some service methods could handle other differences.
i'm writing a system to track observation values from sensors (e.g. temperature, wind direction and speed) at different sites. I'm writing it in C# (within VS2015) using a code-first approach. Although i've a reasonable amount of programming experience, I'm relatively new to C# and the code-first approach.
I've defined my classes as below. I've built a REST api to accept observation reading through Post, which has driven my desire to have Sensor keyed by a string rather than an integer - Some sensors have their own unique identifier built in. Otherwise, i'm trying to follow the Microsoft Contoso university example (instructors - courses- enrolments).
What I am trying to achieve is a page for a specific site with a list of the sensors at the site, and their readings. Eventually this page will present the data in graphical form. But for now, i'm just after the raw data.
public class Site
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Sensor> Sensors { get; set; }
}
public class Sensor
{
[Key]
public string SensorName { get; set; }
public int SensorTypeId { get; set; }
public int SiteId { get; set; }
public ICollection<Observation> Observations { get; set; }
}
public class Observation
{
public int Id { get; set; }
public string SensorName { get; set; }
public float ObsValue { get; set; }
public DateTime ObsDateTime { get; set; }
}
and I've created a View Model for the page I'm going to use...
public class SiteDataViewModel
{
public Site Site { get; set; }
public IEnumerable<Sensor> Sensors { get; set;}
public IEnumerable<Observation> Observations { get; set; }
}
and then i try to join up the 3 classes into that View Model in the SiteController.cs...
public actionresult Details()
var viewModel.Site = _context.Sites
.Include(i => i.Sensors.select(c => c.Observations));
i used to get an error about "cannot convert lambda expression to type string", but then I included "using System.Data.Entity;" and the error has changed to two errors... on the 'include', I get "cannot resolve method 'include(lambda expression)'...". And on the 'select' i get "Icollection does not include a definition for select..."
There's probably all sorts of nastiness going on, but if someone could explain where the errors are (and more importantly why they are errors), then I'd be extremely grateful.
Simply you can you use like
viewModel.Site = _context.Sites
.Include("Sensors).Include("Sensors.Observations");
Hope this helps.
The way your ViewModel is setup, you're going to have 3 unrelated sets of data. Sites, sensors, and observations. Sites will have no inherent relation to sensors -- you'll have to manually match them on the foreign key. Realistically, your ViewModel should just be a list of Sites. You want to do
#Model.Sites[0].Sensors[0].Observations[0]
not something convoluted like
var site = #Model.Sites[0]; var sensor = #Model.Sensors.Where(s => SiteId == site.Id).Single(); etc...
Try doing
viewModel.Site = _context.Sites.Include("Sensors.Observations").ToList();
Eager-loading multiple levels of EF Relations can be accomplished in just one line.
One of the errors you reported receiving, by the way, is because you're using 'select' instead of 'Select'
And lastly, be aware that eager-loading like this can produce a huge amount of in-memory data. Consider splitting up your calls for each relation, such that you display a list of Sensors, and clicking, say, a dropdown will call an API that retrieves a list of Sites, etc. This is a bit more streamlined, and it prevents you from getting held up because your page is loading so much information.
Update
I've created a sample application for you that you can browse and look through. Data is populated in the Startup.Configure method, and retrieved in the About.cshtml.cs file and the About.cshtml page.. This produces this page, which is what you're looking for I believe.
I made a register page with dynamic form in Orchard CMS, and received new requirements of checking record count.
I have no idea about how to do this, I looked into the SubmissionAdminController.cs in Orchard.DynamicForms.Controllers folder, but still could not find a way.
I'm thinking to get the record count from my cshtml view page and check it in different parts, is it possible?
To get the record count of the stored submissions, inject or resolve an IRepository<Submission>, and use the Count() method to count all items. Note that the Count() method accepts an expression, which allows you to filter by form name for example. For reference, this is what the Submission class looks like:
namespace Orchard.DynamicForms.Models {
public class Submission {
public virtual int Id { get; set; }
public virtual string FormName { get; set; }
[StringLengthMax]
public virtual string FormData { get; set; }
public virtual DateTime CreatedUtc { get; set; }
}
}
When you have an IRepository<Submission>, this is how you would count all submissions in a form called "MyForm":
var count = submissionRepository.Count(x => x.FormName == "MyForm");
If you don't have a controller or custom part or anything to inject this IRepository into, then you could resolve the repository directly form your view like this:
#{
var submissionRepository = WorkContext.Resolve<IRepository<Submission>>();
var submissionCount = submissionRepository.Count(x => x.FormName == "MyForm");
}
Make sure to import the proper namespaces:
Orchard.DynamicForms.Models for Submission
Orchard.Data for IRepository<T>
However, if you need to display this number in multiple places, it's best to create a shape so that you can reuse it. Even better would be to not resolve the repository from the shape template directly, but via an IShapeTableProvider. The primary reason for that becomes clear when you start overriding your shape template or start providing shape alternates, both in which cases you'll have duplicate logic in all of your shape templates, which isn't very DRY of course. And there's the more philosophical issue of separation of concerns: you don't want data access code in your views. Rather, use that code from a controller, driver or shape table provider.
I am a newbie and creating a website where you can create your own custom quizes. Ive made a database that stores a class object mytests that consists of a name, and a list of questions parameter.
public class MyTests
{
public int ID { get; set; }
public string name { get; set; }
public string description { get; set; }
public List<MyQuestions> AllTestQuestions;
}
//using this object for questions
public class MyQuestions
{
public string QuestionDescription { get; set; }
public string MultipleChoiceCorrect { get; set; }
public string MultipleChoiceB { get; set; }
public string MultipleChoiceC { get; set; }
public string MultipleChoiceD { get; set; }
public string Answerexplanation { get; set; }
}
I'm using the default database code generated by visual studio. I have no problem adding this test object(mytest) to the database, but what I want to do is that on the edit.cshtml view I want to be able to add elements to the question list before returning the object to the database saved.
The problem is I don't know how to edit the model object from the view, or if this is even possible. I could maybe get it to work through a redirect? but I thought that adding the elements directly from the view would be easier. Is it possible to modify the model.object inside a view from the view (putting security concerns aside)?
For example model.title = something;
or
model.list.add()
Is anything like this possible?
If this question is not clear please let me know and I will try to clarify in the comments.
Yes, it is possible to edit the model from within the view.
From within your .cshtml file specify the view model using the #model declaration, then edit the model like so:
#model Namespace.For.MyTests
#Model.name = "Hello World";
<p>#Model.name</p>
Whilst this would work, it's not really what the view is for so I wouldn't recommend it.
The view is about presenting your data, not mutating it - that should be done in the controller, or domain layer. As soon as the user leaves the page then your changes will be lost due to the stateless nature of the web (.NET MVC passes data to the view from the controller, then ends the request).
This should be done at the controller level. You could do it on a view but it's not what the view is for.
Your issue is that if the page is refreshed you will lose you content, so if you do anticipate on the page refreshing you will need a way in which to temporarily hold the information before it being saved.
On a side note, I'd also consider renaming your classes "MyTests" to "MyTest" (singular) and "MyQuestions" to "MyQuestion"... it's just good practice because then you'd have a List of singleton "MyQuestion" in a "MyTest". EntityFramework Codefirst will pluralise the names when the database is created/update.
Suppose I have a model with 20 fields, and in my index page, I want to list all models that are stored in my database.
In index page, instead of listing all fields of the model, I only to list 3 fields.
So, I make two class:
class CompleteModel {
public int Id { get; set; }
public string Field01 { get; set; }
public string Field02 { get; set; }
public string Field03 { get; set; }
public string Field04 { get; set; }
public string Field05 { get; set; }
...
public string Field20 { get; set; }
}
now, in my Controller, I can use:
await _context.CompleteModel.ToListAsync();
but I feel that it does not seem to be the right way to do it, because I'm getting all fields and using only 3 fields.
So, I made this code:
class ViewModel {
public string Field02 { get; set; }
public string Field04 { get; set; }
public string Field08 { get; set; }
}
var result = _context.CompleteModel.Select(
x => new {
x.Field02,
x.Field04,
x.Field08
}).ToListAsync();
var listResults = new List<IndexViewModel>();
if (result != null)
{
listResults.AddRange(results.Select(x => new IndexViewModel
{
Field02 = x.Field02,
Field04 = x.Field04,
Field08 = x.Field08
}));
}
I think this is a lot of code to do this.
First, I selected all the fields that I want, then, copied everything to another object.
There's a "more directly" way to do the same thing?
Like:
_context.CompleteModel.Select(x => new IndexViewModel { Field02, Field04, Field08 });
You could use AutoMapper to reduce the boiler plate so you're not manually copying field values over.
If you include the AutoMapper NuGet package then you'd need to have the following in your startup somewhere to configure it for your classes:
Mapper.Initialize(cfg => cfg.CreateMap<CompleteModel, ViewModel>());
You could then do something like the following:
var results = await _context.CompleteModel.ToListAsync();
var viewModelResults = results.Select(Mapper.Map<ViewModel>).ToList();
There are a lot of configuration options for the package so do take a look at the documentation to see if it suits your needs and determine the best way to use it if it does.
In my view this is one of the weaknesses of over abstraction and layering. The VM contains the data that is valuable to your application within the context of use (screen, process etc). The data model contains all the data that could be stored that might be relevant. At some point you need to match the two.
Use EF Projection to fetch only the data you need from the database into projected data model classes (using the EF POCO layer to define the query, but not to store the resultant data).
Map the projected classes onto your VM, if there is a naieve mapping, using Automapper or similar. However unless you are just writing CRUD screens a simple field by field mapping is of little value; the data you fetch from your data store via EF is in its raw, probably relational form. The data required by your VM is probably not going to fit that form very neatly (again, unless you are doing a simple CRUD form), so you are going to need to add some value by coding the relationship between the data store and the View Model.
I think concentrating on the count of lines of code would lead to the wrong approach. I think you can look at that code and ask "is it adding any value". If you can delegate the task to Automapper, then great; but your VM isn't really pulling its weight other than adding some validation annotation if you can consistently delegate the task of data model to VM data copying.