Saving complex view model using Entity Framework 4.3 - asp.net-mvc-3

I have Customer, Order and OrderItem tables. OrderItem.OrderID points to Order.ID; and Order.CustomerID points to Customer.ID i.e. the common Customer -> Order -> OrderItem setup.
And I have a view model – Customer which contains Order objects and then OrderItem objects as well.
If the user creates a new Customer, new Order and new OrderItems on a view, which are then bound to the Customer view model object (containing all Customer, Order, OrderItem data); is there a way to save this Customer view model using EF?
My confusion comes from the fact that, since Customer, Order, OrderItem(s) are all new records; which means the Customer.ID (auto-incremented number) has not been generated yet (record not saved yet); so how does EF know what ID to use when saving Order.CustomerID?
Do I need to save Cusomer first, get the Customer.ID, then save Order, then get Order.ID and then save OrderItem(s)?
Thanks.

You just call this:
context.Customers.Add(customer);
context.SaveChanges();
and if everything is correctly configured in your mapping EF will understand relations and correctly save customer first, retrieve its Id and use it for saving related orders. It will handle order items in the same way.

As long as you establish the objects relationships before saving it should work
customer.Orders = new List<Orders>();
customer.Orders.Add(order);
order.OrderItems = new List<OrderItems>();
order.OrderItems.Add(orderItem);
context.Customer.Add(customer);
context.SaveChanges();

Related

Initializing DropDown list from a table

I'm new to MVC4 programming. Followed the NerdDinner tutorial initially. Now am gradually complicating the scenarios. I want to populate a DropDown list from a table's field but don't know how to, although I searched for relevant material from Internet but couldn't get some sophisticated info.
The scenario is that there are 2 tables Software and Category (which represents the category of the software whether it is Anti-Virus, Graphics etc...).
In Software table, catID is in int form which has a foreign key relationship with the catID in Category table.
In Category table, catID and catTitle are the only fields.
Now while creating the Create view to add/upload a new Software, I want that the catTitle of all the catIDs are shown in a Drop-Down List, from which the user will choose the Software category, but I don't know how to do that....
The model being used in my Create.cshtml file is
#model SoftwarePortal.Models.Software
So in this case, what will be the arguments for
#Html.DropDownListFor()
How and where should i specify the SQL stmt to fetch catIDs and corresponding catTitles? (I am using Linq to SQL...)
How to access a table that is not declared as the model of the current View...?
In controller
suppose your Generated database entity will be SoftDBEntities
private SoftDBEntities se = new SoftDBEntities();
public ActionResult Create()
{
//se.Categorys will get all categories
//se.Categorys may be replace with a function which return records from Category table
ViewBag.CatId= new SelectList(se.Categorys, "CatId", "CatTitle");
return View();
}
In cshtml file
#Html.DropDownList("CatId")
if above statement not work then try this
#Html.DropDownListFor(model.CatId,(SelectList)ViewBag.CatId,"CatId","CatTitle")
Oh gosh! Would you believe all that I needed to do was to typecast the ViewBag.Categories to SelectList inside #Html.DropDownListFor()!!! Because it doesn't automatically take the shape of the stored item...
So stupid of me...

Entity Framework: Get Model with Linked Models in Many to Many Relationship

I'm coming from TSQL + C# land and have been trying to adapt to linq and EF. Many-to-many relationships have been tripping me up. I have models with many-to-many relationships that I want to query from a database. Such as:
class Product{
public int ID {get;set;}
public string ProductName {get;set;}
public virtual ICollection<Tag> Tags {get;set;}
}
class Tag {
public int ID {get;set;}
public string TagName {get;set;}
public virtual ICollection<Product> Products {get;set;}
}
I'm able to get a product itself out of the DbContext, and then later fetch it's associated Tags like this:
// product exists in memory as a Product with an empty product.Tags
var query = from p in db.Product
from t in db.Tags
where p.ID == product.ID
select p.Tags;
Then I can assign the product.Tags with the fetched Tags. Obviously, this is very inefficient when dealing with multiple products if I have to query for every product.
With linq and EF, I want to be able to get a Product with all of its associated Tags in one round trip to the database. Also, I want to be able to get all Products and their associated Tags (or a filtered list of Products). How do would the linq look?
Edit:
Ok, after some more fiddling around, I've got this:
var query = db.Product.Include("Tags")
.Where(p => p.Tags.Any(t => t.Products.Select(m => m.ID).Contains(p.ID)));
This is almost what I need. The results are all products with tags. Missing are the products that don't have tags. I think of this as the equivalent of a SQL inner join. I want to left outer join the tags to the product, and return all products with tags optional. How to get all products with their associated tags without excluding products that have no tags?
Edit:
This was easier than I thought.
var query2 = db.Product.Include("Tags").DefaultIfEmpty();
This gets all the products and their respective tags, including products without tags. Hopefully it works for the right reasons...
The purpose of using an object-relational mapper like EF is that it maps relationships for you. If you are manually joining objects that have foreign keys in the database, you are doing it wrong.
See my question Why use LINQ Join on a simple one-many relationship?
The correct answer is simply context.Products.Include("Tags"), which will auto-magically join Products and Tags for you. This is literally the biggest (only?) benefit of using an ORM.

MVC 3 / EF 4.2 - Editing against ViewModel, do I save against Model or ViewModel?

My first MVC3 EF 4.2 site and I'm confused on some things, currently on ViewModels when querying and saving. Please correct me if I explain this poorly, i'm not sure how to term this. The .edmx automatically created the table classes but I read it was better to create a ViewModel, considering I need to join tables to display/edit my Product completely. The controller code below is where I join tables to output a Product to edit, and then save. My question - what is the right way to save the Product, to the Product.cs model generated by DbContext or my own ProductViewModel.cs?
Is there an easier method to query a product and join the tables and then map to the viewmodels parameters, or do I keep doing all this in the controller like below?
I also want to save/update the product each time someone views/clicks on the product, so I wasn't sure if I create a separate ViewModel for updating just that parameter or again, use the Product model.
Hope that makes sense! I can explain further if needed.
private SiteForgeEntities db = new SiteForgeEntities();
public ActionResult Edit(int id)
{
var viewModel = (
from a in db.Products
join b in db.Sites
on a.SiteId equals b.SiteId
join c in db.Sections
on a.SectionId equals c.SectionId
join d in db.Affiliates
on a.AffiliateId equals d.AffiliateId
select new ProductViewModel()
{
ProductId = a.ProductId,
Product = a.Product,
Description = a.Description,
Image = a.Image,
Price = a.Price,
Clicks = a.Clicks,
Link = a.Link,
Site = b.Site,
Section = c.Section,
Affiliate = d.Affiliate
}).Single(x => x.ProductId == id);
return View(viewModel);
}
[HttpPost]
public ActionResult Edit(Product product)
{
...update database...do I pass in and save back to Product or my ProductViewModel
}
You use ViewModel to pass multiple models to the view, but when you save data, you need to save it to the appropriate model. If you are adding or modifying products, you will add items to products (using your DbContext). If you have one-to-many relationship defined between two models (in your Product.cs model you might have a property declared as:
public virtual ICollection<SomeOtherModel> SomeOtherData { get; set; }
you can use this to build a table instead of passing everything in a ViewModel. There is a nice tutorial here regarding the CRUD operations using EF4. Have a look at these short tutorials that can give you an idea about your strategy http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc.

ASP.Net MVC View returned, but how can I show additional information?

I have a SQL database with has the following: Customer, Item, Clothing and Food.
Item holds a key to Clothing or Food.
Item also holds a key to Customer. Therefore a customer can have an item, which may be of food or clothing.
I am using ADO.Net Entity Framework and have this generated automatically.
I currently have the following set-up: A person may enter their ID on the webpage and this is sent via a form post where the controller picks it up and queries the database using LINQ to get the customer. The customer view (details) is then returned. I can now see all the customer details etc.
However, what I want is to be able to see the items the customer has, the different food items and clothing items, but I am unsure how to do this. I also want to be able to allow the user to edit one field of the clothes and food items tables. Any idea how I would implement this?
Here is an ActionResult in my CustomerController:
public ActionResult Details(int id)
{
var cust = (from c in dataModel.Customers
where (c.MembershipID == id)
select c).First();
return View(cust);
}
I can also write cust.Items which is the entity which I want to display in the view with the customer (their items). How would I display this in the view also?
Hopefully this makes it a little more clear on what I am trying to achieve and how.
Thanks.
Using Entity Framework, if you're tables are linked properly with the right foreign keys and all that then your Customer entity should have a property that is a collection of Items.
You could also create your own strongly typed ViewModel that has a field for Customer and implement your own properties for Clothing and Food and populate those with another query.
This question was asked last night but its similar. The guy in the question wanted information to populate a dropdown passed in. You want something similar, not for a dropdown, but to fill in textboxes to edit. How to properly populate drop downs from ViewData in controller on multiple views in ASP.NET MVC
To create a ViewModel start by creating a new class and name it CustomerAndItemsViewModel, for example.
public class CustomerAndItemsViewModel
{
public Customer Customer { get; set; }
public IQueryable<Items> Items { get; set; }
}
public ActionResult Details(int id)
{
var cust = (from c in dataModel.Customers
where (c.MembershipID == id)
select c).First();
var items = (from i in dataModel.Items
where (i.MembershipID == cust.MembershipID)
select i;
return View(new CustomerAndItemsViewModel { Customer = cust, Items = items });
}
And don't forget that you will no longer be passing a Customer to your view. So you need to change the line at the top to something like:
#model Your.Path.To.CustomerAndItemsViewModel
Typically, if you want to pass back information that is not contained in just one of your entities, you have to create a class that encompasses more than one object. So, if you want a page that displays your customer information, and all their items (which they can then edit), you would need to have a the controller action pass back a "CustomerAndItems" object (or something similarly named). This object would hold a reference to the Customer as well as a collection of their Items. (You build the CustomerAndItems object within your Action.)
Then, your view would be strongly typed to CustomerAndItems, and you can then display each piece of information as you normally would.

Spring-Hibernate: How to submit a for when the object has one-to-many relations?

I have a form changeed the properties of my object CUSTOMER. Each customer has related ORDERS. The ORDER's table has a column customer_id which is used for the mapping. All works so far, I can read customers without any problem.
When I now e.g. change the name of the CUSTOMER in the form (which does NOT show the orders), after saving the name is updated, but all relations in the ORDERS table are set to NULL (the customer_id for the items is set to NULL.
How can I keep the relationship working?
THX
UPDATE: Mapping Info
The Orders are mapped on the Customer side
#OneToMany
#JoinColumn(name = "customer_id")
#OrderBy("orderDate")
private Collection<Order> orders = new LinkedList<Order>();
UPDATE
Seems like adding a
#SessionAttributes("customer")
to my model, changing the method to
public String saveTrip(#ModelAttribute("customer") Customer customer, BindingResult result, SessionStatus status) {
if (!result.hasErrors()) {
this.tripManager.saveTrip(trip);
}
else {
logger.debug("Form data included errors, did not save data");
BindingUtils.logBindingErrors(result, logger);
}
status.setComplete();
return "redirect:/customers/";
}
Could solve the issu. But is this a good way of solving it???
One way would be not to submit the CUSTOMER Object from the form.
Instead submit the customer, submit only the customers ID and the new Name. In the controller you have to load the Customer by the submitted ID and then update the Name. And persist the Customer again.
HI,
Make cascade="none" attribute of many-to-one relationship from order side.
Thanks.

Resources