I applied for a job, they required me to create a small MVC app before interview which I did. They rejected it saying that I had used bad practices. Please help me figure out what I did wrong!
The task involved a simple database with a Product and a load of Sales (a one to many).
I had to:
display a list of products with total sales
display and allow edition and deletion of the sales
My solution:
create a left joined SQL view which used a group and join to itself to get the sale totals. This table had one row per product
Create an inner joined SQL view with all of the product and sales data. This had one row per sale.
For #1, I just rendered out the view
For #2, I had to render out product details and sales details (a one to many on a single page) so I did the following in the controller:
public ActionResult Details(int id)
{
// get details for the selected product
var product = db.ProductsWithTotals.Where(q => q.ProductId == id).Single();
ViewData["CatalogueNumber"] = product.CatalogueNumber;
ViewData["Title"] = product.Title;
ViewData["Artist"] = product.Artist;
ViewData["TotalSold"] = product.TotalSold;
ViewData["ProductId"] = product.ProductId;
// then pass its sales lines to the view
var salesLines = db.SalesLineDetails.Where(q => q.ProductId == id);
return View(salesLines);
}
If anyone could explain how I could have done this more gracefully, it'd be greatly appreciated.
The only thing I personally would have done differently is:
Use EF (but yeah, L2S is fine for a quickie like this)
Create a ViewModel class for the details View. I use ViewData as sparingly as possible.
But yeah, nothing bad here and I agree that it was probably not a good place to work at. People also tend to make up vague reasons if they didn't want to say they didn't like your face.
/shrug
Related
I'm working on my first (kinda) big personal project and I am stuck. I have 4 tables, 3 of which have foreign keys linking into tbl_model_details. All tables are listed below.
tbl_model_details
tbl_model_type
tbl_model_name
tbl_model_scale
Ideally I want to show data through my controller with HTTP Get. I can get Postman to to return data from my controller using _context.tbl_model_details.ToList();
Currently Postman is showing the id's for the other tables, but want them to show data from other columns within those tables instead of the id.
Within SQL I was able to build this query which displays the information I would like from the other tables, Is there an equivalent that I could make to run inside my controller? Or is there a way I can use this query that I have already made?
SELECT model_scale, model_name, info, picture, model_type, part_number, amount_owned, modified, limited_addition, date_purchase, price_paid, upc
from tbl_model_details
join tbl_model_type
on tbl_model_details.type_id = tbl_model_type.type_id
join tbl_model_name
on tbl_model_details.name_id = tbl_model_name.name_id
join tbl_model_scale
on tbl_model_details.scale_id = tbl_model_scale.scale_id
Any help from you guys would be great.
Thanks
You can use Entity Frameworks LINQ Include. This will allow you to include the sub-models in the same query:
_context.tbl_model_details
.Include(details => details.tbl_model_type)
.Include(details => details.tbl_model_name)
.ToList();
Without knowing your relationships, DBSet and Model setups, I can say that the statement will look exactly like the one I mentioned, but this may help you get on the right track.
This will allow you to later retrieve data from the sub-models:
#Model.tbl_model_scale.model_scale;
I am working on a company's legacy project. There's a huge object which is constructed by a super long query. The query somehow looks like this.
SELECT *
FROM item i
JOIN item_product prod on prod.item = i.id
LEFT JOIN product_shippingaddress ps on pa.product = prod.id
LEFT JOIN product_packageinfo pp on pp.product = prod.id
.
.
.
(80 lines of query)
WHERE item.id = #itemId
Which is a very long query involves many information about this product.
It constructs a huge object 'Item' which provides all kind of information of the item.
Taking the below example of how things works currently
int itemId = createItem(); //creates a record in item table
associateAddressToItem(item); // Add a shipping address to item
for(int productId in productsToAdd){
addProduct(itemId); // insert info into item_product table
}
Item item = getItem(item); // This function invokes the huge query to collect information of a single item
for(Product product in item.products){
UpdateItemPrice(product.Id,itemId);
if (product.shippable())
{
addItemTax(itemId, product.Id); // add tax based on address and product attribute
}
}
item = getItem(itemId); // calls the query to update information of the object
charge(item); //charge based on item's price and tax
This case invokes the function getItem twice. I don't think this is efficient at all, as long as it runs a huge query twice. However, I think it is needed currently because it needs to fetch information stored in database to update the object.
Is there a better way to handle this kind of situation? I feel it is not optimized but I can come up with a way to improve it.
As long as I got your question right, here's what you do:
Creating an empty record in the table.
Filling in a table (item_product) with some data that you got.
Requesting that data again.
Updating the data.
Requesting that data again. x2
Updating the data. x2
And all of that is done querying the database.
What I suggest you to do:
Update the Item object in memory first, do as much calculation as you can without hitting the database.
Request an ID for the new record.
Update data in the database. Once.
Thus, most of the calculation is performed in memory without running long queries and requesting information you already have.
Every article I need to solve my problem seems to be in C# and I need a solution in VB.NET.
I'm using EF 6.0 with Database First model. Let me use the classic Customer product scenario to demonstrate my situation. In my database I have three tables Customer, Product and CustomerProduct. See this example in this link as mine is exactly the same.
After I generate my model from the database, my entity model diagram shows that the CustomerProduct has disappeared as expected and the the model shows a many to many relationship between Customer and Product also as expected with navigational properties of Products in Customer and Customers in Product.
All I want to do is find the product related to a customer pull out some data from both tables namely CustName and ProductName.
The SQL I would use is:
SELECT c.CustName, p.ProductName FROM Customer c
INNER JOIN CustomerProduct cp on c.CustomerId = cp.CustomerId
INNER JOIN Product p on cp.ProductId = p.ProductId
WHERE c.CustomerId=101
I don't know how to use the Addresses navigational property to access the Address data in one query.
You include them and then access them via the property in the Entity class.
Dim query = model.User.Include("Address").Include("UserAddressLink").Where(Function(o) o.UserId = 101).FirstOrDefault
If Not query Is Nothing Then
Dim houseNumber = query.Address.HouseNo 'uses the navigation property
End If
Thanks to InteXX I managed to work it out. This is my whole solution
Using db as new CustProdEntities
Dim query = db.Customers.Include(Function(U) U.Products).ToList
txtCustomer.Text = query.First.CustName
txtProduct.Text query.First.Products.First.ProdName
End Using
The bit I was stuck on was having to filter twice to the Product data. I'm not sure if there's an easier way to do this but it works for now.
Update take 2
here is the two queries i'm working with (paging is omitted in both queries)
i'd like to get the following query
SELECT *
FROM product
LEFT OUTER JOIN
(
SELECT *
FROM Cart
LEFT OUTER JOIN
cartproducts
ON Cart.Id = cartproducts.Cart_id
WHERE Cart.username = 'user'
)
AS CartFiltered
ON product.Id = CartFiltered.product_id
but i always seem to get
SELECT *
FROM product
LEFT OUTER JOIN
cartproducts
ON product.Id = cartproducts.Product_id
LEFT OUTER JOIN
Cart
ON
cartproducts.cart_id = cart.id
WHERE Cart.username = 'user'
How can i manage to create the first type of query?
I hope my question is clearer :) lack of clarity is sometimes a great enemy of mine :p
Update:
FWIW, i still haven't found the answer, and am currently loading the paged product data and the whole cart to display the correct object.
Crude solution but it works and it beats the combinatorials i've been through trying to make the Criteria API recognize me as its master. I would be very interested if somebody could happen to point me in the right direction though ;)
Hello,
i'm having a hard time writing the following query in the Criteria API, and i don't really see how to do it: i hope some people can help.
On the database, i have products. Theses products can be in many carts (one cart per user), and each cart can contain many products, so we have a manytomany relationship.
I would like to display a list of every product, along with a small icon next to it to inform the user that this particular product is already in the cart. What i did is i asked NHibernate for my products, and to do a left outer join on carts filtered by the cart's owner.
Dim critPage As ICriteria = Session.CreateCriteria(GetType(Product)) _
.SetFirstResult(pageNumber * itemsPerPage).SetMaxResults(itemsPerPage) _
.CreateCriteria("Carts", "c", SqlCommand.JoinType.LeftOuterJoin) _
.SetProjection(plist) _
.SetResultTransformer(New TypedResultTransformer(Of ProductWithCartInfo)) _
.Add(Expression.Eq("c.User", username))
the projection list is here to reduce the number of columns to what's interesting for the ProductWithCartInfo class. It contains only property projections.
The problem is that with this query, the cart filtering is applied to the whole result set and i don't see every product with its presence in the user's cart, but rather every product in the user's cart.
Is it possible to do a left outer join on a subquery with the Criteria API in Nhibernate? For information, i would like to keep it in the Criteria API if possible.
Thanks
I'm not sure I entirly follow your issue but it sounds very similar to an issue I had. I seems that when you have the nested (sub) criteira with NHibernate you loose some of the control. I was able to get around my issue but aliasing my tables instead of using the nested criteira.
Possibly try...
criteria.CreateAlias("Cart", "Cart", JoinType.LeftOuterJoin);
and then your filter on the cart will have to be an OR condition
ICriterion cartCriterion = Restrictions.Eq("Cart.User", username);
customerCriterion = Restrictions.Or(customerCriterion, Restrictions.IsNull("Cart.User"));
criteria.Add(customerCriterion);
Let me know if that helps you out... if not... maybe post the SQL that your criteria above is generating and where it needs to change.
Good Luck
I'm in a databases course and the instructor wants us to develop an e-commerce app. She said we can use any framework we like, and now that we're halfway through the semester she decided that Rails does too much and wants me to explicitly write my SQL queries.
So, what I'd like to do is to write my own functions and add them to the models to essentially duplicate already existing functionality (but with SQL that I wrote myself).
So the questions then become:
How do I execute manually created queries inside the model?
How do I stuff the results into an empty object that I can then return and work with inside the view?
Also, I'm aware of what terrible practice this is, I just don't want to start all over in PHP at this point.
I think, you should know 2-3 really necessary methods, to use it.
(assume we have at least 2 models, Order and User(customer for order))
For example, just to run query on your database use this:
Order.connection.execute("DELETE FROM orders WHERE id = '2')
to get number of objects from your database, the best way is use method "count_by_sql", it's scalable. I'm using it in my projects, where table has over 500 thousands records. All work to count application gives to database, and it did it much more efficient than app.
Order.count_by_sql("SELECT COUNT(DISTINCT o.user_id) FROM orders o")
this query gets number of all uniq users who has an order. we can "JOIN ON" tables, order results using "ORDER BY" and group results.
and the most often use method: find_by_sql
Order.find_by_sql("SELECT * FROM orders")
it returns to you an array with ruby objects.
Lets say you have a purchase
class Purchase < ActiveRecord:Base
def Purchase.find(id)
Purchase.find_by_sql(["Select * from purchases where id=?", id])
end
end
Maybe you want the products for a particular purchase. You can manually define the purchased_items in your Purchase model.
class Purchase < ActiveRecord:Base
def purchased_items
PurchasedItem.find_by_sql(["Select * from purchased_items where purchase_id=?",self.id])
end
end
So for example, in your controller where you now want to get the purchased items for a particular purchase you can now do this
#purchase = Purchase.find(params[:id])
#purchased_items = #purchase.purchased_items
If you need a more raw connection to the database, you can look into ActiveRecord:Base.connection.execute(sql)