C# EF query for typical products - category relationship? - entity-framework

Using entity framework, trying to get some help for a query (prefer method based syntax) for this typical use case:
There is a products table, like:
ownerId
productId
ProductCategoryId
productInfo, etc.
There is a typical product-category-mapping table, like:
somePrimaryKey
ownerId
categoryId
productId
sortOrder
This set up allows one product to be in multiple category, and has its own sort order in each category. Also, we have the "ownerId" in all tables since each owner can only see his own data.
Now, given a categtoryId and ownerId, we need to find all products of this category, sorted by the sortOrder.
Any way how we should write this?
Many Thanks!

You can try to use something along those lines :
// Instanciate your context.
// Do it the way you've already done it, it's here only for example.
DbContext bd = new DbContext();
// The query :
List<Products> listProducts = new List<Products>();
listProducts = db.Products.Where(p => (db.ProductsCategories.Where(pc => pc.CategoryID == categoryID && pc.OwnerID == ownerID).Select(pc => pc.ProductID).OrderBy(pr => pr.sortOrder).ToList()).Contains(p.ProductID)).ToList();
This way use the product-category mapping (categorieID and ownerID are the datas you inject and you keep the sorting.

Related

How to filter records using group functionality in BreezeJs

I'm developing a client app that uses breezejs and Entity Framework 6 on the back end. I've got a statement like this:
var country = 'Mexico';
var customers = EntityQuery.from('customers')
.where('country', '==', country)
.expand('order')
I want to use There may be hundreds of orders that each customer has made. For the purposes of performance, I only want to retrieve the latest order for each customer. This will be based on the created date for the order. In SQL, I could write something like this:
SELECT c.customerId, companyName, ContactName, City, Country, max(o.OrderDate) as LatestOrder FROM Customers c
inner join Orders o on c.CustomerID = o.CustomerID
group by c.customerId, companyName, ContactName, City, Country
If this was run against the northwind database, only the most recent order row is returned for each customer.
How can I write a similar query in breeze, so that it runs on the server side and therefore returns less data to the client. I know I could handle this all on the client but writing some javascript in a querysucceeded method that could be run by the client - but that's not the goal here.
thanks
For a case like this, you should create a special endpoint method that will perform your query.
Then you can use an Entity Framework query to do what you want, using the LINQ syntax.
Here are two Web API examples:
[HttpGet]
public IQueryable<Object> CustomersLatestOrderEntities()
{
// IQueryable<Object> containing Customer and Order entity
var entities = ContextProvider.Context.Customers.Select(c => new { Customer = c, LatestOrder = c.Orders.OrderByDescending(o => o.OrderDate).FirstOrDefault() });
return entities;
}
[HttpGet]
public IQueryable<Object> CustomersLatestOrderProjections()
{
// IQueryable<Object> containing Customer and Order entity
var entities = ContextProvider.Context.Customers.Select(c => new { Customer = c, LatestOrder = c.Orders.OrderByDescending(o => o.OrderDate).FirstOrDefault() });
// IQueryable<Object> containing just data fields, no entities
var projections = entities.Select(e => new { e.Customer.CustomerID, e.Customer.ContactName, e.LatestOrder.OrderDate });
return projections;
}
Note that you have a choice here. You can return actual entities, or you can return just some data fields. Which is right for you depends upon how you are going to use them on the client. If they are just for display in a
non-editable list, you can just return the plain data (CustomersLatestOrderProjections above). If they can potentially
be edited, then return the object containing the entities (CustomersLatestOrderEntities). Breeze will merge the entities
into its cache, even though they are contained inside this anonymous object.
Either way, because it returns IQueryable, you can use the Breeze filtering syntax from the client to further qualify the query.
var projectionQuery = breeze.EntityQuery.from("CustomersLatestOrderProjections")
.skip(20)
.take(10);
var entityQuery = breeze.EntityQuery.from("CustomersLatestOrderEntities")
.where('customer.countryName', 'startsWith', 'C');
.take(10);

Entity Framework Conditional Count of Navigation Property 2 levels down

Just starting out with Entity Framework and am trying to work out how you would do something like this....
Say I have the following entities, Customers that have Orders that have OrderLineItems which are linked to Products. I would like to return the name of every customer with a count of the number of times they have ordered a particular product.
I have seen examples of using .Count() but these have always been for the first navigation property i.e. number of orders per customer.
Would appreciate some guidance here.
Something like this should work, where context is your DbContext instance.
It will return an IEnumerable<dynamic>, although obviously you could make a class to hold the results.
// The product to count
var productId = 12345;
context.Customers.Include("Orders.OrderLineItems.Products")
.Select(customer =>
new {
CustomerName = customer.Name,
ProductCount = customer.Orders
.SelectMany(o => o.OrderLineItems)
.SelectMany(i => i.Products.Where(p => p.Id = productId).Count()
});
The Include() extension method is useful, it will make sure that the resulting SQL query joins the relevant tables together - otherwise multiple queries would be executed for each customer (one to get orders, another for line items and a final one for products).

Entity Framework Return Parent along with child entity as Ieunmerable List

I am new to Entity Framework and had a question i have been stuck on for a while. I have a repository in my DAL to access the data its returning IEnumerable lists for functions defined there. There are two tables involved here table Company and thier Customer_orders please see below for details. I need to return an Ienumerable list for Customer Orders ...which also includes the Customer name. I am able to return everything back for the customer order table but cant get the Customer name from the related table. Is it because I am returning a list of Ienumerable CustomerOrder type? If anyone can provide some help by showing the right code it would be greatly appreciated. Once again I am trying to bind to a grid pulling from the CustomerOrders table but need to also display CustomerName from Customers table.
Table1 (Customers)
company_id
customer_id
customerName
customerAddress
Table 2 (CustomerOrders)
customer_id
product_id
productName
productDesc
This is what I have so far this doesnt pull up any customer Names but pulls the CustomerOrders information
public IEnumerable<CustomerOrders> GetCustomerOrders(int company_id)
{
return context.Customers.Where(c => c.company_id == company_id).First().CustomerOrders.ToList().OrderBy(p => p.ProductName);
}
How about:
return context.CustomerOrders
.Include(o => o.Customer)
.Where(o => o.customer_id == customer_id);

Entity Framework 4.1 Code First - auto increment field on insert for non primary key

My model contains an Order (parent object) and Shipments (child object). The database table for these already have a surrogate key as an auto-increment primary key.
I have the business rule is that for each shipment in the order, we need to have an auto generated "counter" field -- e.g. Shipment 1, Shipment 2, Shipment 3, etc. Shipment model has properties: "ShipmentId", "OrderId", "ShipmentNumber". My attempted implemention is to have ShipmentNumber an int and in code(as opposed to database), query the Shipment collection and do max() + 1.
Here's a code snipet of what I'm doing.
Shipment newShipmentObj = // blah;
int? currentMaxId = myOrderObj.Shipments
.Select(x => (int?) x.ShipmentNumber)
.Max();
if (currentMaxId.HasValue)
newShipmentObj.ShipmentNumber = currentMaxId.Value + 1;
else
newShipmentObj.ShipmentNumber = 1; // 1st one
myOrderObj.Shipments.Add(newShipmentObj);
// etc.. rest of EF4 code
Is there a better way?
I don't really like this as I have the following problems because of potential transaction/concurrency issues.
My Order object also has a autoincrement "counter" -- e.g. Order 1, Order 2, Order 3, ... My Order model has properties: "OrderId", "CustomerId", "OrderNumber".
My design is that I have an OrderRepository but not a ShipmentRepository. The ShipmentRepository could query off the Order.Shipment collection... but with Orders, I have to query directly off the dbcontext, e.g.
int? currentMaxId = (_myDbContext)).Orders
.Where(x => x.CustomerId == 123456)
.Select(x => (int?)x.OrderNumber)
.Max();
However, the above part doesn't work well if I attempt to add multiple objects to the DbContext without committing/saving changes to the database. (i.e. the .Where() returns null... and only works if I use DbContext ".Local", which is not what I want.)
Help! Not sure what the best solution would be. Thanks!
you seem to already have shipmentid that is incremental. you can use it for you shipment number and maybe combined with current date as described here: How to implement gapless, user-friendly IDs in NHibernate? what you are trying to do with Max() is evil. Stay away from it as it can cause problems with getting the same shipment numbers for multiple shipments when the load is high

Entity Framework - How to Set Association Value?

Let's say I have a Person class and an Order class, with foreign keys in the DB. The EF model will mark Person with a List of Orders and Order with a Person instance.
If I want to set the Person for the Order, do I really have to do it with an instance of Person?
Is there not a slimmed down way to do so, say with just a PersonID ?
To assign Person entity to a Order without loading Person entity, you have to do something like this:
var db = new OneToManyEntities();
var Order = new Order { OrderId = 100, OrderName = "Order name" };
Order. PersonReference.EntityKey = new EntityKey("OneToManyEntities.Person ","PersonID",10);
db.AddToOrders(Order);
db.SaveChanges();
Puzzled's answer is correct for EF v1. It's a pain. If you don't mind the extra query, you can set the property succinctly:
int id = 1;
Order.Person = context.Persons.Where(x => x.PersonID == id).FirstOrDefault();
Entity Framework v4 will have "FK Associations", which is a fancy term for directly-settable foreign keys.