Cost must be multiple by 5 - c#

I am working small application with basic CRUD operation and I have Product Model.
In this model I have something like
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public int amountAvailable { get; set; }
public double cost { get; set; }
[ForeignKey(nameof(User))]
public int UserId { get; set; }
public User Users { get; set; }
}
Right now, I need some shortcut or some hack how to make cost (cost of the product), but it should be a multiple of 5, meaning the price can be 5,10,15,20,25,30... etc.
Is there anything which I can force user to put price something like thiss?
I try with [DataAnnotation] and using Range but I think this will not work.

Try:
public class MultipleOf5Attribute : ValidationAttribute
{
public override bool IsValid(object value)
{
return ((int)value) % 5 == 0;
}
}
use the decimal instead of the int

You can make cost variable as a prop and round there any given value by user till it is valid.

You can use a JS at the end of your view which is probably better as you will have a front end validation rather than posting the form before checking if it’s wrong (sorry I’m using my phone to type the suggested answer so may not be formatted properly) but something like this:
<script>
document.getElementById("Submit_btn_id").addEventListener('click',function ()
{
//get the value entered in the input field
var userEnterANumber = document.getElementById('input_id').value
if (userEnterANumber % 5 == 0)
{
console.write('This is a multiple of 5')
//turn off the required attribute from the input field
document.getElementById("input_id").required = false;
}
else
{
console.write('Not a multiple of 5')
//set the required attribute on the input field
document.getElementById("input_id").required = true;
}
});
</script>

Related

Trying to set up Nested Object in C#, with computed field based on list

I am experimenting with a nested object class for an upcoming software project, in C#. I know how to do computed fields/properties within a class, at least as far as setting it programmatically with something like the date.
This is a little different. I am setting up a nested class like this:
string Test { get; set; }
List<Line> Detail { get; set; }
decimal Total {
get {
return TotalOf();
}
}
decimal TotalOf() {
var listQuery = this.Detail;
// This is where I'm trying to figure out how to do.
// I want the TotalOf function to return the sum of the
// Cost fields of the contained list items (Line is defined below).
// I will remove the "return 0;" eventually once
// I can figure out how to do the calculation.
return 0;
}
public class Line {
int indexOf { get; set; }
decimal Cost { get; set; }
}
That way, the field Total is automatically calculated rather than me having to compute it through the code consuming this class.
I have tried searching all over but I can't seem to find the right answer. I have plenty of time to do this, and worst case, I can just do it in the program consuming this class, but I thought I'd ask. When I hit the . after typing in this.Detail, the only aggregate function that comes up is Count.
I have tried to use the Detail.Sum function, hoping the Linq would bring up a lambda expression that I could then say "add up the Cost" but it won't come up.
I know this should be simple but I can't figure it out.
First, set access modifiers for Line properties like as public or other. Because, on default state it is private.
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
Then, set up root class like as LineCollection.
public class LineCollection
{
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
public string Test { get; set; }
public List<Line> Detail { get; set; }
public decimal Total { get; set; }
}
On LineCollection initialize default values for properties on constructor:
public class LineCollection
{
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
public string Test { get; set; }
public List<Line> Detail { get; set; }
public decimal Total { get; set; }
public LineCollection()
{
this.Test = string.Empty;
this.Detail = new List<Line>();
}
}
After this modify get/set accessors for Total property. I guess, property is read only and we not need to define set accessor.
public decimal Total
{
get
{
return this.Detail.Sum(x => x.Cost);
}
}
Code in get accessor automatically runs when we trying to get his value. Finally, we can run tests for checks.
LineCollection collection = new LineCollection();
collection.Detail.Add(new LineCollection.Line() { indexOf = 0, Cost = 43.3m });
collection.Detail.Add(new LineCollection.Line() { indexOf = 1, Cost = 23 });
collection.Detail.Add(new LineCollection.Line() { indexOf = 3, Cost = 56.21m });
Console.WriteLine(collection.Total.ToString());
It returns 122,51.
Think this method would work for you:
decimal TotalOf() {
return this.Detail.Select(line => line.Cost).Sum();
}
I believe this way also works:
decimal TotalOf() {
return this.Detail.Sum(line => line.Cost);
}
Hope this helps :)

Check if an int property has value assigned to it coming from an HTTP request

Good day fellow programmers,
I have a simple domain expressed as follows:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public List<Quote> Quotes { get; set; } = new List<Quote>();
}
and
public class Quote
{
public int Id { get; set; }
public string Text { get; set; }
public Person Person { get; set; } // Just a navigation property.
public int PersonId { get; set; } // The foreign key for Person.
}
I'm working on a PUT endpoint in ASP.NET Core that takes a Quote object from the body of the HTTP request in order to update the quote text. However, I want to make sure that the person who said the quote is not being changed along with the text.
When passed as a JSON, the object looks like this:
{
"id": 69,
"text": "nice quote"
}
Since the PersonId does not necessarily have to be included, it's sent back as null and therefore I must ignore it when comparing to the current value to see if it's different, but the C# compiler won't let me do that because integers are non-nullable value types, making PersonId == null a meaningless statement.
So my question is: is there a way to check for the "valueless" of an integer without using int? in the POCO class?
Let me know if any further information is needed. Thank you.
You could check for the default value of int, which is 0. I'm assuming in some sort of data store, you will never have a person ID equal to 0 (or even less than 0).
public void Put(Quote quote)
{
if (quote.PersonId == default)
{
// person id is the default value of int (0)
}
}

c# use a function on a generic type with ViewModel

Is this possible? I am trying to avoid a lot of copying and pasting from area to area. I have a search function (I have reduced the code for simplicity).
if (!String.IsNullOrEmpty(filterVM.searchString))
{
var nameSearch = filterVM.searchString.ToLower();
guests = guests.Where(g => g.FirstName.ToLower().StartsWith(nameSearch)
|| g.LastName.ToLower().StartsWith(nameSearch)
)
}
filterVM.FilteredResultsCount = guests.CountAsync();
Guests can change from area to area, but it always has the same base things, like FirstName and LastName,
ex:
public class GuestBasicBase
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string GuestGuid { get; set; } = Guid.NewGuid().ToString();
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then I can have a bigger class for a particular area like
public class AreaOneGuest : GuestBasicBase
{
public int ID {get; set;}
public string ExtraFieldOne { get; set; }
public string ExtraFieldTwo { get; set; }
//Etc
}
I would like to have a function which will return a viewmodel and part of that viewmodel is PaginatedList and the other part is the Filter parameters, like this:
public class GuestBasicBaseIndexVM
{
public PaginatedList<T:GuestBasicBase> Guests { get; set; }
public GuestIndexFilterVM FilterVM { get; set; }
}
And I want a function to return this but take in a larger field, like
public async Task<GuestBasicBaseIndexVM>(T:GuestBasicBase, GuestIndexFilterVM filterVM){
//do search function
return (T where T: GuestBasicBase)
}
Does this question make sense and is it possible? Currently trying on my own and seeing what happens...I feel like it is sort of like the PaginatedList class but I am not certain
Not exactly what I wanted, but here is what I did. changed my BaseViewModel like this:
public class GuestBasicBaseIndexVM
{
public IEnumerable<GuestBasicBase> Guests { get; set; }
//Changed from a PaginatedList
public GuestIndexFilterVM FilterVM { get; set; }
}
and this function:
public static async Task<GuestBasicBaseIndexVM> CreateUpdatedGuestList(GuestIndexFilterVM filterVM, IQueryable<GuestBasicBase> guests)
{
//Code to search through guests and return filtered list and filters viewmodel
}
Then after the Ienumaerable of basic guests is returned I did this to connect them back to the AreaOne Guests
var x = await Helpers.CreateUpdatedGuestList(filterVM, guests);
var hsIDs = x.Guests.Select(v => v.GuestGuid).ToHashSet(); //Filtered GuestGuids to hashset
areaOneGuests = guests.Where(g => hsIDs.Contains(g.GuestGuid)) //This matches up the filtered list of base guests to the actual full guests.
//Then whatever code to do what I want with the AreaOne Guests....
It wasn't exactly what I was trying to do, but still saves me a lot of copying and pasting from area to area with similar base Guest classes. Have not been able to measure any noticeable performance loss/gain doing it this way.

MongoDB and Asp Core update only a key: value pair instead of whole model

In our app we have a user model linked to a mongoDB database. My question is about modifying only a value from key/value pair inside a given user data (of course using the User ID).
Here is my simple model:
public class User
{
[BsonId]
public string Id { get; set; }
public string email { get; set; } = string.Empty;
public bool hasAcceptedTerms { get; set; } = false;
public int state { get; set; } = 0;
public int UserId { get; set; } = 0;
public IList<UserFile> SubmittedFiles { get; set; }
}
public class UserFile
{
public int fileID { get; set; }
public bool hasFile { get; set; }
}
On our app, after authenticate the user for the first time, we create his entry in the Mongo Database using
public async Task AddUser(User item)
{
await _context.Users.InsertOneAsync(item);
}
After his first login we want to update the fact he accepted Terms: by doing so we want to change hasAcceptedTerms to true and move the state key from 0 to 1.
For the moment in our Repository we have something like:
public async Task<UpdateResult> UpdateUser(string id, User item)
{
return await _context.Users
.ReplaceOneAsync(n => n.Id.Equals(id)
, item
, new UpdateOptions { IsUpsert = true });
}
But by doing so we must provide a full item corresponding to our model.
I don't find any way to create a function which I could use like:
UdateUserData(string id, string data, bool newvalue);
For example call UpdateUserData('user1objectidhash', 'hasAcceptedTerms', true) would modify the correct value for the user identified by his ObjectID Id.
First problem: is typing data as string a good idea/unique solution? I don't find my function call being elegant by typing the data key as a string.
2nd: I don't know what will be the type of newvalue because it will depend on what is the data I want to modify. Can I detect it from model?
3rd: I don't know the correct Mongo.Driver function which can process this update.
Could you give me some cues and tips?
If you just want to update not whole object, but some properties it's possible to do this Update command:
collection.UpdateOneAsync(x=>x.Id ==id,
Builders<User>.Update.Set(u=>u.hasAcceptedTerms, false)
.Set(u=>u.state, 1));
I assume, that collection is your IMongoCollection<User> , that you mean with _context.Users

How to validate textboxes in ASP.NET MVC

I am new to ASP.NET MVC and am trying to validate a text-box. Basically, if user inputs less than 2 or a non number how can I get the error to display. Here's the tutorial I am trying to follow.
I have my code below.
Create View:
<%= Html.ValidationSummary()%>
<%= using (HtmlBeginForm()){%>
<div class="half-col">
<label for="Amount">Amount:</label>
<%= Html.TextBox("Amount")%>
<%= Html.ValidationMessage("Amount", "*")%>
</div>
Create Controller:
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude ="ID")] Charity productToCreate)
{
//Validation
if (productToCreate.Amount < 2)
ModelState.AddModelError("Amount, Greater than 2 please");
return View(db.Donations.OrderByDescending(x => x.ID).Take(5).ToList()); //Display 5 recent records from table
}
Model:
public class Charity
{
public int ID { get; set; }
public string DisplayName { get; set; }
public DateTime Date { get; set; }
public Double Amount { get; set; }
public Double TaxBonus { get; set; }
public String Comment { get; set; }
}
Error:
CS1501 No overload for method 'AddModelError' takes 1 CharitySite
You are adding the error to your modelstate incorrectly. You can read more about the ModelStateDictionary on the MSDN
AddModelError takes 2 parameters, so you would want:
ModelState.AddModelError("Amount", "Greater Than 2 Please.");
Having said that, you can use attributes to validate your model properties so you don't have to write all of that code by hand. Below is an example using the Range attribute. The RegularExpression attribute could also work. Here is an MSDN article containing information about the different types of attributes.
public class Charity
{
public int ID { get; set; }
public string DisplayName { get; set; }
public DateTime Date { get; set; }
[Range(2, Int32.MaxValue, ErrorMessage = "The value must be greater than 2")]
public Double Amount { get; set; }
public Double TaxBonus { get; set; }
public String Comment { get; set; }
}
Also as a side note, the tutorial you are following is for MVC 1&2. Unless you HAVE to use / learn that. I would recommend following the tutorial for MVC 5 here.
Change this line:
ModelState.AddModelError("Amount, Greater than 2 please");
to:
ModelState.AddModelError("Amount ", "Amount, Greater than 2 please");
The first parameter is the member of the model being validated; it can be an empty string just to indicate an error not associated to a field. By specifying the Amount field, internally it uses that to highlight the erroring field (the control should have input-validation-error CSS class added to it) if you are using all of the client-side validation pieces.
ModelState.AddModelError takes 2 arguments, not 1. Link to MSDN ModelStateDictionary.AddModelError Method.
ModelState.AddModelError("Amount", "Greater than 2 please");
if (productToCreate.Amount < 2)
ModelState.AddModelError("Amount", "Greater than 2 please");

Categories