I cannot add the orders to the database - asp.net-core-mvc

I am building an e-store with ASP.NET Core. I've created CRUD operations to add my products and save it to the database, it is working fine. Then I wanted to save the orders from the customers to my database, sadly I couldn't manage to do so.
When I click a button, it saves the order to the database and sends the customer to the thank you page.
Can you please check my code and tell me where am going wrong.
This is my OrderController:
[HttpPost]
public async Task<IActionResult> PlaceOrder([FromBody] Order model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var order = new Order
{
OrderDate = DateTime.Now,
Name = model.Name,
Address = model.Address,
Email = model.Email,
PhoneNo = model.PhoneNo
};
var orderDetails = new List<OrderDetails>();
foreach (var item in model.OrderDetails)
{
orderDetails.Add(new OrderDetails
{
ProductId = item.ProductId,
// Quantity = item.Quantity,
// Price = item.Price,
Order = order
});
}
using (var context = new AppDbContext(_dbContextOptions))
{
context.Order.Add(order);
context.OrderDetails.AddRange(orderDetails);
await context.SaveChangesAsync();
}
// returns a HTTP 200 OK response to the client indicating that the operation was successful.
return Ok();
}
and this is the button from my view:
<p>
<a asp-controller="Order" asp-action="PlaceOrder" class="btn btn-primary addToCart">Place my order</a>
</p>
Order class:
public class Order
{
public Order()
{
OrderDetails = new List<OrderDetails>();
}
public int Id { get; set; }
[Display(Name = "Order No")]
public string OrderNo { get; set; }
[Required]
public string Name { get; set; }
[Required]
[Display(Name = "Phone Number")]
public string PhoneNo { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
public string Address { get; set; }
[Display(Name = "Today's Date")]
public DateTime OrderDate { get; set; }
public virtual List<OrderDetails> OrderDetails { get; set; }
}
Order details class
public class OrderDetails
{
public int Id { get; set; }
[Display(Name = "Order")]
public int OrderId { get; set; }
[Display(Name = "Product")]
public int ProductId { get; set; }
[ForeignKey("OrderId")]
public Order Order { get; set; }
[ForeignKey("PorductId")]
public Product Product { get; set; }
}

Related

Loading data from three related tables in ASP.NET Core using Entity Framwork Core in one-to-many relationship makes some data not displayed

I have three tables Customer, Loan and LoanHistories. Customer table is related to Loan table in a one-to-many relationship, and the Loan table is related to LoanHistories in one-to-many relationship as well.
The following are the C# classes for these tables:
public class Customer
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name = "ID NO")]
public int CustomerID { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Phone Number")]
public string PhoneNo { get; set; }
[Display(Name = "Nearest Primary School")]
public string NearestPrimarySchool { get; set; }
[Display(Name = "Photo")]
public string Photo { get; set; }
public ICollection<Loan> loans { get; set; }
// public IEnumerable<LoansHistories> loansHistories { get; set; }
// public ICollection<WorkForLiving> workForLivings { get; set; }
// public ICollection<CustomersCharacterBehavior> customersCharacterBehaviors { get; set; }
}
public class Loan
{
[Key]
public int LoanID { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "money")]
public decimal LoanAmount { get; set; }
[NotMapped]
public decimal TotalRepaidIn { get; set; }
[NotMapped]
public decimal Balance { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "money")]
[Display(Name = "Loan Balance")]
private decimal _LoanBalance;
public decimal LoanBalance
{
get { return LoanAmount * interestRate; }
set { _LoanBalance = value; }
}
[Display(Name = "Interest Rate")]
public decimal interestRate { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Application Date")]
public DateTime ApplicationDate { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Disbursement Date")]
public DateTime DisbursmentDate { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Due Date")]
public DateTime DueDate { get; set; }
[Display(Name = "Defaulted")]
public bool Defaulted { get; set; }
[Display(Name = "Approved")]
public bool Approved { get; set; }
//Navigation property
public int CustomerID { get; set; }
public Customer customer { get; set; }
//public ICollection<LoanComments> loancomments { get; set; }
public ICollection<LoansHistories> loansHistories { get; set; }
}
public class LoansHistories
{
[Key]
public int HistID { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "money")]
[Display(Name = "Repaid Amount")]
public decimal RePaidIn { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Repayement Date")]
public DateTime RepayementDateDate { get; set; }
[Display(Name = "No of paying interest only")]
public int NoOfPayinyingIntrestOnly { get; set; }
// Navigation properties
public int LoanID { get; set; }
public Loan loan { get; set; }
// Navigation property
// public int CustomerID { get; set; }
// public Customer customer { get; set; }
}
This is the LoansController that loads data from Loans and LoansHistories tables:
[HttpGet]
public async Task<ActionResult<IEnumerable<Loan>>> Getloans()
{
var data = await _context.loans
.Include(lh => lh.loansHistories)
.Select(l => new Loan()
{
TotalRepaidIn = l.loansHistories.Select(lh => lh.RePaidIn).Sum(),
Balance = l.loansHistories.Select(lh => lh.RePaidIn).Sum()-l.LoanAmount,
loansHistories = l.loansHistories,
ApplicationDate = l.ApplicationDate,
Defaulted = l.Defaulted,
DisbursmentDate = l.DisbursmentDate,
DueDate = l.DueDate,
LoanID = l.LoanID,
Approved = l.Approved,
interestRate = l.interestRate,
LoanAmount = l.LoanAmount
}).ToListAsync();
return data;
}
This is the data in JSON format:
[
{
"loanID":1,
"loanAmount":1000.0000,
"totalRepaidIn":202700.0000,
"balance":201700.0000,
"loanBalance":15000.000000,
"interestRate":15.00,
"applicationDate":"2022-03-28T00:00:00",
"disbursmentDate":"2022-03-28T00:00:00",
"dueDate":"2022-04-28T00:00:00",
"defaulted":false,
"approved":true,
"customerID":0,
"customer":null,
"loansHistories":[
{
"histID":1,
"rePaidIn":500.0000,
"repayementDateDate":"2022-03-28T00:00:00",
"noOfPayinyingIntrestOnly":1,
"loanID":1,
"loan":null
}
]
}
]
I want to load data from customer controller but I found entity TotalRepaidIn to be Zero, How can I make it return a value has its returning in loan controller? without having entity totalRepaidIn":0.0
Customer controller:
// GET: api/CustomersApi
[HttpGet]
public async Task<ActionResult<IEnumerable<Customer>>> Getcustomers()
{
return await _context.customers.Include(l=>l.loans).ThenInclude(h=>h.loansHistories).ToListAsync();
}
It returns the following Json data:
[
{
"customerID":30290122,
"firstName":"Isaac",
"lastName":"Kiplagat",
"phoneNo":"0724797768",
"nearestPrimarySchool":"Mokwo",
"photo":"photo",
"loans":[
{
"loanID":1,
"loanAmount":1000.0000,
"totalRepaidIn":0.0,
"balance":0.0,
"loanBalance":15000.000000,
"interestRate":15.00,
"applicationDate":"2022-03-28T00:00:00",
"disbursmentDate":"2022-03-28T00:00:00",
"dueDate":"2022-04-28T00:00:00",
"defaulted":false,
"approved":true,
"customerID":30290122,
"loansHistories":[
{
"histID":1,
"rePaidIn":500.0000,
"repayementDateDate":"2022-03-28T00:00:00",
"noOfPayinyingIntrestOnly":1,
"loanID":1
}
]
}
]
}
]
One way is like the previous did you can select the new Customer instance and set value for it one by one.
Another easier way, you can change your property to below to calculate the RePaidIn:
using System.Linq; //import this namespace...
public class Loan
{
[Key]
public int LoanID { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "money")]
public decimal LoanAmount { get; set; }
private decimal _TotalRepaidIn;
[NotMapped]
public decimal TotalRepaidIn
{
get { return loansHistories.Sum(sum => sum.RePaidIn); }
set { _TotalRepaidIn = value; }
}
//other properties
public ICollection<LoansHistories> loansHistories { get; set; } = new List<LoansHistories>();
}
And in your LoansController, you can improve the action to below:
var data = await _context.loans.Include(lh => lh.loansHistories).ToListAsync();
Customer Controller can also get the correct value for TotalRepaidIn.

There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'Dept_IDs'

The dropdown works fine. It fetches the values from the database but when i insert the selected value into a table. It gives me the error, tried a lot of different ways but didn't work.
View:
#Html.DropDownList(model => model.Dept_ID, ViewBag.deptlistname as
SelectList, "Please select a department");
Controllers:
public ActionResult UserRegistration()
{
HREntities4 db = new HREntities4();
var getdeptlist = db.departments.ToList();
SelectList list = new SelectList(getdeptlist, "Dept_ID",
"Dept_ID");
ViewBag.deptlistname = list;
return View();
}
Post:
[HttpPost]
public ActionResult UserRegistration(UserRegistration model)
{
if (ModelState.IsValid)
{
var details = new HREntities4();
details.logins.Add(new login{
FirstName = model.FirstName,
LastName = model.LastName,
Username = model.Username,
Email = model.Email,
Password = model.Password,
PhoneNumber =model.PhoneNumber,
Address = model.Address,
Hire_Date = model.Hire_Date,
Salary = model.Salary,
Dept_ID = model.Dept_ID
});
details.SaveChanges();
ModelState.AddModelError("updated", "User has been registered");
}
return View();
}
ViewModel:
public partial class UserRegistration
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string PhoneNumber { get; set; }
public string Address { get; set; }
public string Hire_Date { get; set; }
public Nullable<double> Salary { get; set; }
public int Dept_ID { get; set; }
}
Remove the 's' from Dept_IDs because in your UserRegistration model you have Dept_ID.

Count total based on a foreign key value using LINQ

I'm trying to do something like the following done in SQL
SELECT COUNT(*) AS "Total"
FROM dbo.Items
WHERE CategoryID IN (SELECT CategoryID
FROM Categories
WHERE Name = 'Beverages')
Any ideas how we accomplish this in LINQ?
*Update
Item class code:
public class Item
{
[Key]
public int ItemID { get; set; }
public virtual Category Category { get; set; }
public virtual Brand Brand { get; set; }
public int CategoryID { get; set; }
public int BrandID { get; set; }
[Display(Name ="Product Name")]
[Required(ErrorMessage = "Product name is required")]
public string ItemName { get; set; }
[Display(Name="Product Price")]
public decimal? ItemPrice { get; set; }
[DataType(DataType.ImageUrl)]
[Display(Name = "Image URL")]
public string ImageUrl { get; set; }
}
Category class code:
public class Category
{
public int CategoryID { get; set; }
[DisplayName("Category Name")]
public virtual string Name { get; set; }
public virtual List<Item> Items { get; set; }
}
Update
Models
public class Item
{
[Key]
public int ItemID { get; set; }
public Category Category { get; set; }
public int CategoryID { get; set; }
public int BrandID { get; set; }
[Display(Name = "Product Name")]
[Required(ErrorMessage = "Product name is required")]
public string ItemName { get; set; }
[Display(Name = "Product Price")]
public decimal? ItemPrice { get; set; }
[DataType(DataType.ImageUrl)]
[Display(Name = "Image URL")]
public string ImageUrl { get; set; }
}
public class Category
{
[Key]
public int CategoryID { get; set; }
public virtual string Name { get; set; }
public virtual List<Item> Items { get; set; }
}
Sample of data used
You want item's where category = Beverages
You can make it from items end
var itemsCount1 = dbcontext
.Items
.Count(x => x.Category.Name == "Beverages");
You can make it from categories end
//if there is no Category with the name Beverages return 0
var itemsCount2 = dbcontext
.Categories
.FirstOrDefault(x => x.Name == "Beverages")?.Items?.Count() ?? 0;
Query Result
You could get Count with following.
var results = Categories.Where(x=>x.Name.Equals("Beverages")
.Join(Items,
c=>c.CategoryID,
i=>i.CategoryID,
(c,i)=> i).Count();
For mock data,
var Categories = new List<Category>
{
new Category{CategoryID =1, Name ="Beverages"},
new Category{CategoryID =2, Name ="One"},
new Category{CategoryID =3, Name ="Two"}
};
var Items = new List<Item>
{
new Item{ItemID=3,CategoryID=4,ItemName="abc1"},
new Item{ItemID=1,CategoryID=1,ItemName="abc2"},
new Item{ItemID=1,CategoryID=1,ItemName="abc3"},
new Item{ItemID=1,CategoryID=1,ItemName="abc4"},
new Item{ItemID=1,CategoryID=1,ItemName="abc5"},
new Item{ItemID=2,CategoryID=1,ItemName="abc6"},
new Item{ItemID=3,CategoryID=4,ItemName="abc7"},
new Item{ItemID=4,CategoryID=2,ItemName="abc8"},
};
Output : 5
Update
var results = dbContext.Categories.Where(x=>x.Name.Equals("Beverages")
.Join(dbContext.Items,
c=>c.CategoryID,
i=>i.CategoryID,
(c,i)=> i).Count();

Complex Linq to Entities Query

I have done simple LINQ queries but I am stumped on the 2 I need to create now. Basically I am going to get a class ID sent in. I will post the classes the entities are based on below.
public class ScheduledClass
{
public ScheduledClass()
{
Attendees = new List<ClassAttendee>();
}
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[HiddenInput(DisplayValue = false)]
[Required(ErrorMessage = "Please enter a topic")]
public int ClassTopicID { get; set; }
[Display(Name = "Topic")]
public virtual ClassTopic ClassTopic { get; set; }
[HiddenInput(DisplayValue = false)]
public int ClassTypeID { get; set; }
[Display(Name = "Class Type")]
public virtual ClassType ClassType { get; set; }
[Required]
[DataType(DataType.Date)]
[Display(Name = "Class Date")]
public DateTime ClassDate { get; set; }
[Display(Name = "Attendees")]
public virtual ICollection<ClassAttendee> Attendees { get; set; }
}
public ClassTopic()
{
Products = new List<ClassTopicProduct>();
}
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[Required(ErrorMessage = "Please enter a title")]
public string Title { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Display(Name = "Products")]
public virtual ICollection<ClassTopicProduct> Products { get; set; }
}
public class ClassTopicProduct
{
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[HiddenInput(DisplayValue = false)]
public int ClassTopicID { get; set; }
[ForeignKey("ClassTopicID")]
public ClassTopic ClassTopic { get; set; }
[HiddenInput(DisplayValue = false)]
public int ProductID { get; set; }
[ForeignKey("ProductID")]
public ProductType ProductType { get; set; }
}
public class CustomerEmail
{
public CustomerEmail()
{
CustomerEmailModules = new List<CustomerEmailModule>();
}
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[HiddenInput(DisplayValue = false)]
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public string Name { get; set; }
public string Email { get; set; }
[DataType(DataType.PhoneNumber)]
public string PhoneNumber { get; set; }
[Display(Name = "Product Update")]
public Boolean SendProductUpdateEmail { get; set; }
[Display(Name = "Expiration ")]
public Boolean SendExpirationEmail { get; set; }
[Display(Name = "Products")]
public virtual ICollection<CustomerEmailModule> CustomerEmailModules { get; set; }
}
public class CustomerEmailModule
{
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[HiddenInput(DisplayValue = false)]
public int CustomerEmailID { get; set; }
public CustomerEmail CustomerEmail { get; set; }
[HiddenInput(DisplayValue = false)]
public int? ProductID { get; set; }
[ForeignKey("ProductID")]
public ProductType ProductType { get; set; }
}
EDIT___________________________
public class ProductType
{
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[Required(ErrorMessage = "Please enter a product type description")]
public string Description { get; set; }
public virtual ICollection<ProductTypeDetail> ProductDetails { get; set; }
}
EDIT_________________________________
So I am basically trying to send emails to people who might be interested in an upcoming class. Each class has a class topic. The class topic has 1 or more products associated with them. When I get the Class ID I need to go get all of the products associated with the class topic for the class. Once I have that I need to go look at CustomerEmails. Each CustomerEmail has any number of products that they are interested in associated with them. I need to find any CustomerEmail that has CustomerEmailModules where the PRoductID = Any of the product IDs in the Class Topic Products results. Here is what I tried to do below that is not working.
public JsonResult GetEmailClassInterest(int id)
{
var classprods = UoW.ScheduledClasses
.Where(o => o.ID == id)
.Select(p => new
{
p.ClassTopic.Products
});
var customeremails = from p in UoW.CustomerEmails where classprods.Any(z => z.Products.Any(x => x.ID == p.ID)) select p.Email;
return Json(customeremails, JsonRequestBehavior.AllowGet);
}
The query seems to run through ok but I get no results and there shoudl be base don the data I have. If anyone can tell me what I am doing wrong I would appreciate it.
Thanks
Try doing this:
var classprods = UoW.ScheduledClasses
.Where(o => o.ID == id)
.SelectMany(sched => sched.ClassTopic.Products.Select(prod => prod.ProductID));
var customerEmails = UoW.CustomerEmailModules.Include("CustomerEmails")
.Where(mod => mod.ProductID != null && classprods.Contains(mod.ProductID)
.Select(mod => mod.CustomerEmail.Email);

MVC3 db.SaveChanges() INSERT statement error

I am following MVC music store similarly. http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-9
When I doing create orderDetails, I have got error with inner exception.
Could you help me what does it mean?
"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_OrderDetails_Product\". The conflict occurred in database \"rentalDB\", table \"dbo.Product\", column 'productId'.\r\nThe statement has been terminated."
Do I need to check in SQL Server? I don't know why it errors happen..
Can you give me some advice? I am giving you some my code.
Please help me. Thanks.
public int CreateOrder(Order order)
{
decimal orderTotal = 0;
var cartItems = GetCartItems();
// Iterate over the items in the cart, adding the order details for each
foreach (var item in cartItems)
{
var orderDetail = new OrderDetails
{
productId = item.Product.productId,
orderId = order.orderId,
unitPrice = item.priceValue,
rentalPeriod = item.rentalPeriod,
startDate = item.dateCreated.AddDays(2),
endDate = item.dateCreated.AddDays(2 + item.rentalPeriod),
quantity = item.count
};
// Set the order total of the shopping cart
orderTotal += (item.count * item.priceValue);
db.OrderDetails.Add(orderDetail);
}
// Set the order's total to the orderTotal count
order.total = orderTotal;
// Save the order
db.SaveChanges(); //I have error in here!!!
// Empty the shopping cart
EmptyCart();
// Return the OrderId as the confirmation number
return order.orderId;
}
Here is viewModel
public class ShoppingCartViewModel
{
public List<Cart> CartItems { get; set; }
public decimal CartTotal { get; set; }
}
Here is Cart
public class Cart
{
[Key]
public int recordId { get; set; }
public string cartId { get; set; }
public int productId { get; set; }
public decimal priceValue { get; set; }
public int count { get; set; }
public int rentalPeriod { get; set; }
public DateTime dateCreated { get; set; }
public virtual Product Product { get; set; }
}
Here is Product
public class Product
{
[Key] public int productId { get; set; }
[Required(ErrorMessage = "Please select category")]
public int categoryId { get; set; }
[Required(ErrorMessage = "Please fill in model name")]
[DisplayName("Model name")]
public String model { get; set; }
[DisplayName("Description")]
public String description { get; set; }
[DisplayName("Original price")]
public decimal price { get; set; }
[Required(ErrorMessage = "Please fill in stock of product")]
[DisplayName("Stock")]
public int stock { get; set; }
public virtual Category Category { get; set; }
}
I did not set FK in OrderDetails..
That's what I have got error before.
When I create FK between OrderDetails and Order, it will work.

Resources