I have very complex code. I'm developing a web application for many restaurants where people can order online. I have two tables and models for Order, which contains information about User, and OrderDetails which has MenuItems. I created ShoppingCartController which has a ProcessOrder action
public ActionResult ProcessOrder(FormCollection frc)
{
List<Cart> lstCart = (List<Cart>)Session[strCart];
Order order = new Order()
{
Name = frc["Name"],
UserId = User.Identity.GetUserId(),
OrderTime = DateTimeOffset.UtcNow,
PaymentType = "Cash",
Status = "Processing"
};
db.Orders.Add(order);
db.SaveChanges();
foreach (Cart cart in lstCart)
{
OrderDetail orderDetail = new OrderDetail()
{
OrderId = order.Id,
MenuId = cart.Menu.Id,
Quantity = cart.Quantity,
Price = cart.Menu.Price,
RestaurantId = cart.Menu.RestaurantId
};
db.OrderDetails.Add(orderDetail);
db.SaveChanges();
}
Session.Remove(strCart);
return View("OrderSuccess");
}
Also I created an OrderController for displaying list of orders:
public ActionResult Index(int? restaurantId = null)
{
var orders = db.Orders.Include(o => o.User)
.Include(p => p.OrderDetails)
.OrderByDescending(x => x.Id);
return View(orders.ToList());
}
Here I just added restaurantId parameter.
And now I want to display orders by RestaurantId. I thought about taking RestaurantId from OrderDetails->Menu->RestaurantId, but I don't think that it works because OrderDetails of each order can have many RestaurantId.
Should I add RestaurantId column in Order table? Can you suggest an approach?
Order detail has both orderId and RestaurantId thats the table you need to query from!
Related
I have made a working application that shows contacts from database, allows editing and deleting them and each of their emails/telephones/tags.
Database looks like this:
Contacts - Id (P), Name, Surname, Address;
Emails - EntryId (P), PersonId, Email1;
Telephones - EntryId (P), PersonId, Telephone1;
Tags - EntryId (P), PersonId, Tag1;
(where P means primary key and PersonId is always the corresponding Id from Contacts table, of the person whose email that is)
I haven't connected my tables in any way, I just approched Email of a person with id ID like this, for example:
var mailsById = contactsData.Emails.Where(x => x.PersonId == ID).ToList();
Now I realized I should maybe add a foreign key to tables Emails, Telephones, Tags, which would be the PersonId connected to Id from table Contacts. So I added this to table definitons on Emails:
CONSTRAINT [FK_Emails_Contacts] FOREIGN KEY ([PersonId]) REFERENCES [dbo].[Contacts] ([Id])
(same with Telephones and Tags)
Everything went well, in the EDMX diagram it now shows (1,*) connections between Contacts table and every other table (which I wanted), but now I get an 500 (Internal Server Error) on the following function. Function returns complete info about all the contacts in the database (on the frontend, I have a table Name-Surname-Address-Emails-Telephones-Tags, that's why I'm connecting all the tables from database to one list).
public JsonResult getAll()
{
using (ContactsDBEntities contactsData = new ContactsDBEntities())
{
List<Contact_Info> completeList = new List<Contact_Info>();
var contacts = contactsData.Contacts;
var emails = contactsData.Emails;
var telephones = contactsData.Telephones;
var tags = contactsData.Tags;
//GroupJoin:
//Outer.GroupJoin(Inner, outer => key, inner => key, (outer, inner) => result)
//first join joins contacts table with emails table
var contactList = contacts.GroupJoin(emails,
contact => contact.Id,
email => email.PersonId,
(contact, email) => new
{
Id = contact.Id,
Name = contact.Name,
Surname = contact.Surname,
Address = contact.Address,
Email = email
});
//second join joins telephones to the existing contacts-emails list
var contactList2 = contactList.GroupJoin(telephones,
contact => contact.Id,
telephone => telephone.PersonId,
(contact, telephone) => new
{
Id = contact.Id,
Name = contact.Name,
Surname = contact.Surname,
Address = contact.Address,
Email = contact.Email,
Telephone = telephone
});
//third join creates the needed contacts-emails-telephones-tags list
var contactList3 = contactList2.GroupJoin(tags,
contact => contact.Id,
tag => tag.PersonId,
(contact, tag) => new
{
Id = contact.Id,
Name = contact.Name,
Surname = contact.Surname,
Address = contact.Address,
Email = contact.Email,
Telephone = contact.Telephone,
Tag = tag
});
//contactList3 to completeList
foreach(var contact in contactList3)
{
Contact_Info temp = new Contact_Info();
temp.Id = contact.Id;
temp.Name = contact.Name;
temp.Surname = contact.Surname;
temp.Address = contact.Address;
foreach (var em in contact.Email)
{
temp.Emails.Add(em);
}
foreach (var tel in contact.Telephone)
{
temp.Telephones.Add(tel);
}
foreach (var tag in contact.Tag)
{
temp.Tags.Add(tag);
}
completeList.Add(temp);
}
return Json(completeList, JsonRequestBehavior.AllowGet);
}
}
This is my Contact_Info class which is used in this function:
public class Contact_Info
{
public Contact_Info () {}
public Contact_Info (string name, string surname, string address, List<Email> emails, List<Telephone> telephones, List<Tag> tags)
{
Name = name;
Surname = surname;
Address = address;
Emails = emails;
Telephones = telephones;
Tags = tags;
}
public int Id;
public string Name;
public string Surname;
public string Address;
public List<Email> Emails = new List<Email>();
public List<Telephone> Telephones = new List<Telephone>();
public List<Tag> Tags = new List<Tag>();
}
I tried debugging server side code, it returns no exeptions :/ This is the error output: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Can you maybe tell me what I need to change in the working application if I changed this foreign-key properties of tables? Is it too late to be doing it now (i.e. does it require changing my code radically), and how important are the foreign key constraints here? This is my first use of databases in a more complex code, so please have understanding if I made some please-don't-do-that mistakes :)
Thanks a lot!
If navigation properties exist between your entities (ie. you generated the edmx from the database and FK constraints exist), then you don't need to get the entities individually and then join them. Just use Include():
var contacts = contactsData.Contacts
.Include(x=>x.Emails)
.Include(x=>x.Telephones)
.Include(x=>x.Tags)
.ToList();
I think Include is part of the System.Data.Entity namespace.
I want to invoke method durning mapping my domain class to DTO class but after many tries with LINQ to Entities or LINQ to objects i have failed and i'm getting weird different errors. Actulal error is just a "LINQ to Entities does not recognize the method 'System.String ResizeToLogoImage(System.String)' method, and this method cannot be translated into a store expression.".
Mapping method:
public async Task<SingleCategory> SingleCategoryMapping(EventerApiContext context, int id)
{
var category = await context.Category.Select(c => new SingleCategory
{
CategoryId = c.CategoryId,
CategoryName = c.CategoryName,
CityId = c.CityId,
Events = context.Event.ToList().Where(e=>e.CategoryId == id).Select(e=> new EventForSingleCategory
{
EventId = e.EventId,
EventName = e.EventName,
EventLogo = ImageProcessor.ResizeToLogoImage(e.EventDetail.EventImage.EventImageBase64)
}).ToList()
}).SingleOrDefaultAsync(c => c.CategoryId == id);
return category;
}
Method to be invoked.
public static string ResizeToLogoImage(string base64String)
{
if (base64String == null)
{
return "NULL";
}
var imageToResize = Base64ToImage(base64String);
var resizedImage = ScaleImage(imageToResize, 50, 50);
return ImageToBase64(resizedImage, imageToResize.RawFormat);
}
I know error is appearing during EventLogo property mapping but i have no more idea what to do.
Try to get the data first, before you do the Select statement. I suspect that it is trying to execute ResizeToLogoImage on the database :)
I have a simple example
I want to display a list of companies and employees
ACME
David
Simon
Zac
Microsoft
Kevin
Paul
Currently I do a linq query that returns the company model then traverse the model tree to get the employees. This works fine, however using glimpse I see its doing in the above example 3 queries. One for company then 2 queries for employees one for each company.
Im wondering if I would be better off having a ViewModel representing the data and populating that. However when trying to build the view model I dont know how to build it without doing multiple queries.
var data =
from company in db.Companies
join employee in db.Employees on company.companyId equals employee.companyId
orderby company.name, employee.name
select new { companyName = company.name, employeeName = employee.name }
Is there an easy way to link this to the view model or is there another best practice way of doing something simple like this.
You can get data in one round trip from database by adding ToList():
var data =
(from company in db.Companies
join employee in db.Employees on company.companyId equals employee.companyId
orderby company.name, employee.name
select new { companyName = company.name, employeeName = employee.name }).ToList();
or get company type instead of anonymous type
var data = db.Companies.Include(t => t.Employees )
.Select(t => new
{
t.name,
Employees = t.Employees .Select(p => new { p.name})
}).ToList();
or if you wanna use ViewModel, create a viewmodel:
public class CompanyVm
{
public string name { get; set; }
public IEnumerable<Employee> Employees{ get; set; }
}
public class Employee
{
public string name { get; set; }
}
then use automapper to map data
var comVm = data
.Select(comp => AutoMapper.Mapper.DynamicMap(comp, comp.GetType(), typeof(CompanyVm)))
.Select(comp => comp as CompanyVm).ToList();
Assuming you have the navigation properties in Entity Framework wired up correctly, you should be able to do:
var data = db.Companies
.Include(i => i.Employees)
.Tolist();
Then you can loop through them:
foreach (var company in data)
{
foreach (var employee in company.Employees)
{
}
}
Don't forget to include using System.Data.Entity; or you won't be able to use the strong-typed .Include() method.
I am new in Mvc3 my problem is when i simply create MultiSelectList from the data base its working fine but i want to search on the basis of MultiSelectList selected values i cant handle how to do this
http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and-jquery/using-the-dropdownlist-helper-with-aspnet-mvc
using above link i am able to create MultiSelectList
kindly help me how to search records on the basis of selected values from MultiSelectList
my question is that should i create another View to fetch record from database but problem is what will be the database query to select records
If you look at the sample source code, you can see that they load the list of countries into a multiselectlist:
public ActionResult MultiCountryVM() {
return View(new CountryViewModel());
}
public ActionResult MultiSelectCountry() {
ViewBag.Countrieslist = GetCountries(null);
return View();
}
private MultiSelectList GetCountries(string[] selectedValues) {
List<Country> Countries = new List<Country>()
{
new Country() { ID = 1, Name= "United States" },
new Country() { ID = 2, Name= "Canada" },
new Country() { ID = 3, Name= "UK" },
new Country() { ID = 4, Name= "China" },
new Country() { ID = 5, Name= "Japan" }
};
return new MultiSelectList(Countries, "ID", "Name", selectedValues);
}
Then on the form post they store the selected values into the ViewBag:
[HttpPost]
public ActionResult MultiSelectCountry(FormCollection form) {
ViewBag.YouSelected = form["Countries"];
string selectedValues = form["Countries"];
ViewBag.Countrieslist = GetCountries(selectedValues.Split(','));
return View();
}
It looks like they are putting it into a ViewBag so they can pass it to the MultiCountryVM view, and not actually doing any query with the data. If you wanted to do a query, you would just create a LINQ query using an appropriate context, which you'd also have to write since they only have context for the music entities.
I'd like to know how to run this query in Linq way.
UPDATE orders SET shipDate = '6/15/2012' WHERE orderId IN ('123123','4986948','23947439')
My Codes,
[HttpGet]
public void test()
{
EFOrdersRepository ordersRepository = new EFOrdersRepository();
var query = ordersRepository.Orders;
// How to run this query in LINQ
// Query : UPDATE orders SET shipDate = '6/15/2012' WHERE orderId IN ('123123','4986948','23947439')
}
EFOrdersRepository.cs
public class EFOrdersRepository
{
private EFMysqlContext context = new EFMysqlContext();
public IQueryable<Order> Orders
{
get { return context.orders; }
}
}
EFMysqlContext.cs
class EFMysqlContext : DbContext
{
public DbSet<Order> orders { get; set; }
}
Actually it's pretty easy check the following code
EFOrdersRepository db = new EFOrdersRepository();
int[] ids= new string[] { "123123", "4986948", "23947439"};
//this linq give's the orders with the numbers
List<Order> orders = db.Order().ToList()
.Where( x => ids.Contains(x.orderId.Contains));
foreach(var order in orders)
{
order.ShipDate = '06/15/2012';
db.Entry(usuario).State = EntityState.Modified;
}
db.SaveChanges();
Something like this should work (warning Pseudo code ahead!!)
EDIT I like using the Jorge's method of retrieving the orders better (using contains), but leaving this here as another alternative. The statements below the code sample still hold true however.
[HttpGet]
public void test()
{
EFOrdersRepository ordersRepository = new EFOrdersRepository();
var query = ordersRepository.Orders.Where(x=>x.orderId == '123123' ||
x.orderId == '4986948' || x.orderId = '23947439').ToList();
foreach(var order in query){
var localOrder = order;
order.ShipDate = '06/15/2012';
}
ordersRepository.SaveChanges();
}
Basically, LINQ does not do 'bulk updates' well. You either have to fetch and loop through your orders or write a stored procedure that can take an array of ids and bulk update them that way. If you are only doing a few at a time, the above will work ok. If you have tons of orders that need to be updated, the ORM probably will not be the best choice. I look forward to see if anyone else has a better approach.
Disclaimer: the var localOrder = order line is to ensure that there are no modified closure issues. Also, ReSharper and other tools may have a less verbose way of writing the above.
Note: You need to call SaveChanges from your DBContext at the end
Short answer:
var f = new[] { 123123, 4986948, 23947439 };
var matchingOrders = orders.Where(x => f.Contains(x.ID)).ToList();
matchingOrders.ForEach(x => x.ShipDate = newDate);
Complete test:
// new date value
var newDate = new DateTime(2012, 6, 15);
// id's
var f = new[] { 123123, 4986948, 23947439 };
// simpulating the orders from the db
var orders = Builder<Order2>.CreateListOfSize(10).Build().ToList();
orders.Add(new Order2 { ID = 123123 });
orders.Add(new Order2 { ID = 4986948 });
orders.Add(new Order2 { ID = 23947439 });
// selecting only the matching orders
var matchingOrders = orders.Where(x => f.Contains(x.ID)).ToList();
matchingOrders.ForEach(x => Console.WriteLine("ID: " + x.ID + " Date: " + x.ShipDate.ToShortDateString()));
// setting the new value to all the results
matchingOrders.ForEach(x => x.ShipDate = newDate);
matchingOrders.ForEach(x => Console.WriteLine("ID: " + x.ID + " Date: " + x.ShipDate.ToShortDateString()));
Output:
ID: 123123 Date: 1/1/0001
ID: 4986948 Date: 1/1/0001
ID: 23947439 Date: 1/1/0001
ID: 123123 Date: 6/15/2012
ID: 4986948 Date: 6/15/2012
ID: 23947439 Date: 6/15/2012
In ORMs, You have to fetch the record first make the change to the record then save it back. To do that, I will add an UpdateOrder method to my Repositary like this
public bool UpdateOrder(Order order)
{
int result=false;
int n=0;
context.Orders.Attach(order);
context.Entry(order).State=EntityState.Modified;
try
{
n=context.SaveChanges();
result=true;
}
catch (DbUpdateConcurrencyException ex)
{
ex.Entries.Single().Reload();
n= context.SaveChanges();
result= true;
}
catch (Exception ex2)
{
//log error or propogate to parent
}
return result;
}
And i will call it from my Action method like this
int orderId=123232;
var orders=ordersRepository.Orders.Where(x=> x.orderId.Contains(orderId)).ToList();
if(orders!=null)
{
foreach(var order in orders)
{
order.ShipDate=DateTime.Parse('12/12/2012);
var result= ordersRepository.UpdateOrder();
}
}
In this Approach, if you have to update many number of records, you are executing thatn many number of update statement to the database. In this purticular case, i would like to execute the Raw SQL statement with only one query using the Database.SqlQuery method
string yourQry="UPDATE orders SET shipDate = '6/15/2012'
WHERE orderId IN ('123123','4986948','23947439')";
var reslt=context.Database.SqlQuery<int>(yourQry);