I have two tables in my database that I am filling via Web API:
Orders
________
OrderID
OrderDate
OrderStatusID
and
OrderItems
___________
OrderID
ItemID
ItemVersionID
ItemNote
ItemSortOrder
I need to insert Order and all the items for that order in two tables. OrderID is an identity field generated by the database that I will need for inserting data into OrderItems table.
Primary key for the OrderItems table is a composite key (OrderID, ItemID, ItemVersionID), it is important since the same order can contain multiple items with the same ID but different Version ID.
I was wondering if I will have to add Order and OrderItems data separately or can do so in a single controller function.
Below are my model classes:
[Table("SN_Orders")]
public class Order
{
[Key]
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public int OrderStatusID { get; set; }
public List<OrderItem> Details { get; set; }
}
[Table("SN_OrderItems")]
public class OrderItem
{
[Column(Order = 0), Key]
public int ItemID { get; set; }
[Column(Order = 1), Key]
public int ItemVersionID { get; set; }
[Column(Order = 2), Key]
public int OrderID { get; set; }
public string ItemNote { get; set; }
public int ItemSortOrder { get; set; }
}
And below is my attempt to pass in a list of OrderItems with Order that did not work out:
[HttpPost]
public IHttpActionResult PostItemToOrder(myClass.Order ord1, List<myClass.OrderItem> itemList)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
using (MyContext ctx = new MyContext())
{
ctx.Orders.Add(ord1);
ctx.SaveChanges();
foreach (var item in itemList)
{
item.OrderID=ord1.OrderId;
ctx.OrderItems.Add(item);
ctx.SaveChanges();
}
}
}
Is that something that is possible to accomplish at once? Or will I have to insert order first, return the OrderID to the calling program and then insert Items?
Put it like this:
Your Order class should have:
public class Order
{
public int Id { get; set; }
// all rest
public virtual ICollection<OrderItem> Items { get; set; } // here is the trick
}
[HttpPost]
public IHttpActionResult PostItemToOrder(myClass.Order ord1, List<myClass.OrderItem> itemList)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
using (MyContext ctx = new MyContext())
{
var order = ord1;
order.Items = itemList;
ctx.Orders.Add(order);
ctx.SaveChanges();
}
}
Related
I have a application where stores can complete a questionnaire. within this application i have two tables db.StoreAud(pk:AuditId) which contains all the stores information, and db.storequests(pk:ReviewId) which holds the all questions information.
AuditId is a foreign key in db.storequests table. Now here is the issue if a store complete the questionnaire the data saves perfectly in the database, however is the same store does the questionnaire again the db.storequests creates a new row in the database with a new primary key value instead of updating the previous row. Question is how can i update the previous row if the same store does the same questionnaire again. hope this made since.
db.StoreAUD
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Column(Order = 1)]
public int AuditId { get; set; }
public string Date { get; set; }
public int StoreNumber { get; set; }
public string StoreName { get; set; }
db.storequests
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ReviewId { get; set; }
public int AuditId { get; set; }
public int QuestionOne { get; set; }
public string QuestionTwo { get; set; }
public string QuestionThree { get; set; }
public string QuestionFour { get; set; }
controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(StoreQuestions storequestions)
{
if (ModelState.IsValid)
{
StoreAudit findingAudit = db.StoreAudit.Find(storequestions.AuditId); // grabbing the id from th store audit table
findingAudit.ReadOnlyTickBox = true;
db.StoreQuestions.Add(storequestions);
db.SaveChanges();
return RedirectToAction("Details", "Audit", new { id = storequestions.AuditId });
}
return View(storequestions);
}
I would seperate your update logic into a new Update action, following the Single Responsibility Principle:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Update(StoreQuestions storequestions)
{
if (ModelState.IsValid)
{
StoreAudit findingAudit = db.StoreAudit.Find(storequestions.AuditId);
findingAudit.ReadOnlyTickBox = true;
// update objects here
db.SaveChanges();
return RedirectToAction("Details", "Audit", new { id = storequestions.AuditId });
}
return View(storequestions);
}
}
I am a .NEt student trying to build a simple pizza webbshop. I am using Entityframework to build the database. The errormessage I get is this:
The MERGE statement conflicted with the FOREIGN KEY constraint "FK_Products_Categories_CategoryID". The conflict occurred in database "TomasosPizzeria", table "dbo.Categories", column 'CategoryID'.
The statement has been terminated.
I have googled and tried to solve this pne alone by renaming the properties back and forth. Here are my classes:
public class Product
{
public int ID { get; set; }
public string ProductName { get; set; }
public int ProductPrice { get; set; }
public string Ingridients { get; set; }
//--
public List<OrderDetail> OrderDetails { get; set; }
[ForeignKey("Categories")]
public int CategoryID { get; set; }
public virtual Category Categories { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
List<Product> Products { get; set; }
}
I am using a DbInitializer to set som test values. I have had problems giving the product object a category with the corresponding value.
var categories = new Category[]
{
new Category{CategoryName="Pizza"},
new Category{CategoryName="Pasta"},
new Category{CategoryName="Sallad"},
};
var products = new Product[]
{
new Product{ProductName="Äcklig Calzone", Ingridients="Gamla tomater, möglig ost, trötta oliver, Unken skinka", ProductPrice=150},
new Product{ProductName="Italiensk skit", Ingridients="Proscutti, halvfärdig mozzarella, trötta oliver, skämd vattnig proscutti", ProductPrice=250},
new Product{ProductName="La bussola", Ingridients="Äckliga tomater, giftiga räkor, levande musslor, rutten skinka",CategoryID = 2,<--Here-- ProductPrice = 105 }
};
foreach (Product s in products)
{
context.Products.Add(s);
}
context.SaveChanges();
I am thankful for all the help I get. Please tell me if you wish to see any more of my code.
Solved it by giving CategoryID to the two other products.
I have two related Entity Framework 6 classes in my data layer.
public class Order
{
public int Id { get; set; }
public virtual SalesStatus SalesStatus { get; set; }
}
public class SalesStatus
{
public SalesStatus()
{
Orders = new List<Order>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Order> Orders { get; set; }
}
public class OrderVM
{
public int Id { get; set; }
public SalesStatus SalesStatus { get; set; }
}
I am using Automapper to map these to my view models and back again.
cfg.CreateMap<Order, OrderVM>()
.MaxDepth(4)
.ReverseMap();
The status entity is used to populate a drop down list.
In my method I am taking the selected value and trying to update the order record to the new selected status.
private bool SaveOrderToDb(OrderVM orderVM)
{
using (var db = new MyContext())
{
var order = AutomapperConfig.MapperConfiguration.CreateMapper().Map<OrderVM, Order>(orderVM);
order.SalesStatus = db.SalesStatuses.Find(Convert.ToInt16(orderVM.SalesStatusSelectedValue));
db.Set<Order>().AddOrUpdate(order);
db.SaveChanges();
}
return true;
}
This does not update the relationship in the database. Why? What am I missing?
I have three tables
Products { pid, pname, price }
Orders { oid, odate }
OrderDetails { odid, oid, pid, qty, total }
I've a form which upon submission passes an array of OrderDetails which I want to store in database. But the tragedy here is I want to store current date in Order table at the same time. Now my Order table is getting populated with odate but nothing is getting inserted in my orderdetails table. And I'm using web api and the array is fetched correctly in controller. I guess this line
aOrder.AllOrders.Add(od);
in the controller has to be replaced with somethting else.
Order.cs
public class Order
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int oid { get; set; }
[DataType(DataType.DateTime)]
public DateTime odate { get; set; }
public virtual List<OrderDetail> AllOrders { get; set; }
public Order()
{
AllOrders = new List<OrderDetail>();
}
}
OrderDetail.cs
public class OrderDetail
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int odid { get; set; }
public int oid { get; set; }
public virtual Order order { get; set; }
public int pid { get; set; }
public int qty { get; set; }
public int total { get; set; }
public virtual Product Aproduct { get; set; }
public OrderDetail()
{
Aproduct = new Product();
}
}
OrderDetailsController.cs
private static readonly IOrderDetailRepository _orders = new OrderDetailRepository();
public Order Post(List<OrderDetail> orderDetails)
{
Order aOrder = new Order();
foreach(OrderDetail orderDetail in orderDetails)
{
OrderDetail od = new OrderDetail();
od.oid = orderDetail.oid;
od.pid = orderDetail.pid;
od.qty = orderDetail.qty;
od.total = orderDetail.total;
aOrder.AllOrders.Add(od);
}
aOrder.odate = DateTime.Now;
return _orders.Add(aOrder);
}
OrderDetailRepository.cs
public Order Add(Order order)
{
_db.Orders.Add(order);
_db.SaveChanges();
return order;
}
Can you try specifying a foreign key for OrderDetails:
public class OrderDetail
{
[ForeignKey("Order")]
public int oid { get; set; } //I'm guessing this is Order's PK
Is there a way of using the Contains method in Entity Framework 4 with the actual id of the object?
Take these entities as an example:
public class Order
{
public int OrderId { get; set; } // PK
public string CustomerId { get; set; } // FK to Customer
}
public class OrderItem
{
public int OrderId { get; set; } // PK
public int ItemId { get; set; } // PK, FK to Item
}
public class Item
{
public int ItemId { get; set; } // PK
public string ItemName { get; set; }
}
and I want to return a list of all orders that have item '5' in them.
I want to be able to do:
List<Order> orders = db.Orders.Where(m => m.OrderItems.Contains(5)).ToList()
But that won't work because Contains needs an actual OrderItem object.
Thanks
var orders = db.Orders.Where(m => m.OrderItems.Any(i => i.OrderId == 5)).ToList();
Try this:
List<Order> orders = db.Orders.Where(m => m.OrderItems.Any(i=>i.OrderId==5)).ToList()
OR
List<Order> orders = db.OrderItems.Where(m => m.OrderId==5).Orders.ToList()