Domain Driven Design: Order and Order line Classes - c#

We know in a Database Model, Order and Orderline are generally two separate tables. When modelling the Domain Driven Classes, should they be generally be 1 Denormalized Class or separate classes?
One Domain Class:
public class Order
{
public int OrderHeaderId { get; set; }
public int CustomerId { get; set; }
public int OrderLineNumber { get; set;}
public int ProductId { get; set; }
public int Quantity { get; set;
}
Separated like Database:
public class OrderHeader
{
public int OrderHeaderId { get; set; }
public int CustomerId { get; set; }
public int OrderLineNumber { get; set;}
public virtual ICollection<OrderLine> OrderLine{ get; set; }
}
public class OrderLine
{
public int OrderLineNumber { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set;
public virtual ICollection<OrderHeader> OrderHeader { get; set; }
}
DDD - Aggregate Root - Example Order and OrderLine

You should try to focus on the design and not worry too much about persistence from the get-go. In terms of the Order/OrderLine example it is a rather well-known structure and represents a couple of design elements that are interesting.
When performing object modelling you most certainly don't need to flatten anything unless it really has to. I take the order example slightly further and include any value objects that are only ever related to the aggregate root as nested classes in the root class, like this:
public class Order
{
public Guid Id { get; }
public Guid CustomerId { get; }
public DateTime DateRegistered { get; }
private readonly List<Item> _items = new List<Item>();
public Order(Guid id, Guid customerId, DateTime dateRegistered)
{
Id = id;
CustomerId = customerId;
DateRegistered = dateRegistered;
}
public IEnumerable<Item> GetItems() => _items.AsReadOnly();
public void AddItem(Guid productId, string description, decimal count, decimal unitPrice)
{
_items.Add(new Item(productId, description, count, unitPrice));
}
public class Item
{
// get-only properties
internal Item(Guid productId, string description, decimal count, decimal unitPrice)
{
}
}
}
There are variations but you should implement it in a way that you are comfortable with. I prefer not to use aggregate instances when adding related objects such as the Product since that would mean my repository would need to somehow get to a Product when hydrating the Order instance. One could have overloaded methods for AddItem where one takes the productId and the other a Product where the product.Id is used but I see little value in that.
The interesting thing about the Order->Item scenario is that the OrderItem table, in an entity-relationship model sense, is an associative entity (or link-table) between Order and Product. However, we are all quite comfortable when dealing with this relationship and "know" that the items are related closer to the order and we model it as such. The reason I mention this is that one runs in many such scenarios where the side you need to pick to create a one-to-many relationship is not quite a evident.

If you are aiming for an object-oriented design, you should not concern yourself too much with data. Objects should have behavior.
If the objects are supposed to have behavior, it becomes easier to decide what is an object and what isn't. Does the OrderLine have something to actually do? If not, then it shouldn't exist. "Doing" here means something that directly contributes to some business function, not storing and retrieving data.

Related

How to prevent creating relations by EntityFramework Core

I am making a school project which is a shop.
I have created a Product class:
public Guid Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public string PhotoUrl { get; set; }
public int Quantity { get; set; }
and an Order class:
public Guid Id { get; set; }
public List<Product> Products { get; set; }
public decimal TotalPrice { get; set; }
//address
public string Street { get; set; }
public string HouseNumber { get; set; }
public string PostCode { get; set; }
public string City { get; set; }
public Order()
{
Products = new List<Product>();
}
As you see in Order.cs there is a list of Products, but entity framework always sets a relationship between my product and a order but I just want to add a Product to this list with no relation ship.
As a response I want to get something like this
{
"id" :"someID",
"products": [
{
first product
},
{
second product
}]
}
etc. How can I prevent creating by ef relationships and do simple lists?
Or how can I do a relationship many products to many orders?
You can add the NotMapped attribute to the Property:
...
[NotMapped]
public List<Product> Products { get; set; }
...
You will need to import System.ComponentModel.DataAnnotations
Either I'm missing something, or you are trying to do something that doesn't make much sense. You say there is no relation - but you do want to save both Order and it's Products to the database? That means that there IS relation (of 1:N kind) and EF is right to create it. It can't work without it.
You didn't include full output that you expect, only the Order part with first_product and second_product placeholders. If the placeholders look like your Product class, just let EF create the relation and you are done. If you want them to look different in JSON (omit some properties for example), you should still let EF create the relation, and then write transformation from your Entity classes (Product, Order) to DTO classes (ProductDTO, and OrderDTO that has List<ProductDto>). Which is good practice anyway, even if Entity and DTO match 1:1, in real project it rarely stays that way for long.

How to specify a list of foreign keys in Entity Framework?

How can I specify with data annotation or fluentapi, a list of string in my model like a list of foreign keys? I know that I could specify the User model in the list, but I'd like to have a list of strings.
Model Example:
public class Allocation
{
[Key]
public int Id { get; set; }
...
public List<string> Users { get; set; }
}
public class User
{
[Key]
public string Id { get; set; }
...
}
Even expert developers FAIL MISERABLY when it comes to Entity Framework, so I'll let you into a little secret. Write the code you wish you had.
With regards directly to your scenario, you're over complicating things unnecessarily. Let Entity Framework do it's job and handle the relationships for you!
All you should need to model this relationship is...
public class Allocation
{
public int Id { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public virtual Allocation Allocation { get; set; }
}
Now please note that I DID NOT write the code I wish I had, but that's because the code I wish I had was overkill for this question, and very high-level. If you do however want to delve into this subject and find out what Entity Framework really can do for you, I would start here...
https://lostechies.com/jimmybogard/2010/02/04/strengthening-your-domain-a-primer/

Filling list with different types of objects

I'm working on a recommendation algorithm which all works fine. But now I wanted to implement this code into the branch of my development team.
I'll start from the top. My algorithm can recommend 2 types of objects, restaurants and dishes.
Restaurant:
public class Restaurant
{
public Guid Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public List<Tag> Tags { get; set; } = new List<Tag>();
public int PriceRange { get; set; }
}
And dish:
public class Dish
{
public Guid Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public virtual Restaurant rest { get; set; }
[ForeignKey("rest")]
public Guid RestaurantId { get; set; }
public List<Tag> Tags { get; set; }
}
Now my product owner wants the list to be like this when it's being presented on the home page of our app:
[Restaurant][Dish][Restaurant][Dish] Etc...
So basically, he wants to alternate the type of object that's being recommended. These dishes and restaurants are completely separate. They are generated by my algorithm purely on the user's preferences and have no correlation with eachother at all.
Now my problem is how to return such a list. I figured I'd need a wrapper class which contains either a Restaurant or Dish like this:
public class RecommenderItem
{
public Restaurant rest { get; set; }
public Dish dish { get; set; }
}
This way I can create a List<RecommenderItem> and return that to the client. The client would only need to check which attribute is null and retrieve the values from the one that is not.
I'm just unsure if this is the correct approach. Are there any 'best practices' in doing this? Let me know if I should elaborate more!
If they doesn't have common base class then creating one wrapper class is the best solution. At the same time you can be more flexible and create something like
public class RecommendationItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public string PageUrl { get; set; }
public object Entity { get; set; }
}
So you can include all common information in this class and client will not be required to check with which object type he works. In such case it would be easier to add one more item type. At the same type I added reference to entity itself - it can be used if some specific handling for one or two item types is required.
You can declare an interface IRecommenderItem:
public interface IRecommenderItem
{
//shared properties
}
public class Restaurant : IRecommenderItem
{
}
public class Dish : IRecommenderItem
{
}
than, you can type:
List<IRecommenderItem> m = new List<IRecommenderItem>();
If you are going to connect pairs of elements it always makes sense to me to... well, pair the elements. I am assuming that each dish is specific to a particular restaurant? So the list would be [Restaurant1][Dish for Restaurant1][Restaurant2][Dish for Restaurant2]...?
I like the previous answer by oryol creating a common base class as well.
So, your RecommenderItem class is fine. But fill in both properties and pass a list of pairs back. Expand the list into the full set of items for display by creating a new List, iterating through the list of RecommenderItems and adding Restaurant and Dish from each entry in it.

Designing tables to avoid circular reference

Working in one project (Catering theme ) when I was designing the database I didn't take care about some thing , and now Is very hard to avoid some kine of errors(Circular error).
Suppose I have following scenario :
I have Meal object that should be composed from a list of semi-finished products (we will call it Product ) and list of simple Resources.
One Product is composed from a list of Resoruces and list of products.
So in real example this will look like this:
Meal: Pizza that contains list of Resoruces(cheese,dough) and list of Products : in our case will be just :Sauce.
Sauce will be composed from List of Resources(salt,Some cheese ,tomato Sauce) and a List of Products (in our case will be just one "Chopped tomatoes with salt")
So now I have following classes:
public class Resource
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ProductToProduct
{
public int Id { get; set; }
public Product MainProduct { get; set; }
public Product Component { get; set; }
public double Quantity { get; set; }
}
public class ProductToResource
{
public int Id { get; set; }
public Product Product { get; set; }
public Resource Resource { get; set; }
public double Quantityt { get; set; }
}
public class Meal
{
public int Id { get; set; }
public string Name { get; set; }
public IList<MealToProduct> MealToProducts { get; set; }
public IList<MealToResource> MealToResources { get; set; }
}
public class MealToResource
{
public int Id { get; set; }
public Meal Meal { get; set; }
public Resource Resource { get; set; }
public double Quantity { get; set; }
}
public class MealToProduct
{
public Meal Meal { get; set; }
public Product Product { get; set; }
public double Quantity { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public IList<ProductToResource> ProdcutToResources { get; set; }
public IList<ProductToResource> ProductToProducts { get; set; }
}
My problem is in relation between Product to Product.
Suppose I will have Product1, Product2 , Product3 , Product4.
Product 1 will be composed from something and Prodcut2, Product4.
Product2 will be composed from something and Prodcut3.
Prodcut 3 will be composed from something and Prodcut4.
Prodcut 4 will be composed from something and Prodcut1 , in this case when I will try to calcualte Cost for Product1 , or Product 4 I will get an Circular error.
So my problem is in ProductToProduct table.
My question is how I must to design tables to avoid this kind of errors .
I AM VERY SORRY FOR MY EXPLICATION BUT IT IS VERY HARD TO EXPLAIN THIS PROBLEM.
PLEASE ASK ME IF SOMETHING IS UNCLEAR.
THANKS FOR YOUR ATTENTION.
Note:This is not so important for this case but I am working in ASP.Net mvc , orm is Fluent Nhibernate.
Here's an example of a function you could use to detect whether a parent-child relationship exists. I have assumed that the product relationships are described in a table called ProductLink, which has two foreign keys to Product: ParentProductId and ChildProductId.
This function uses a recursive query to determine the complete list of products which are children of the product denoted by the argument #ParentProductId, then does a simple test to see whether #ChildProductId appears in that list.
create function dbo.ProductRelationshipExists
(
#ParentProductId int,
#ChildProductId int
)
returns bit
as
begin
declare #ChildExists bit = 0;
with ProductChildCTE as
(
-- Base case: Get the parent's direct children.
select ChildProductId from ProductLink where ParentProductId = #ParentProductId
-- Recursive case: Get the children's children.
union all
select
ProductLink.ChildProductId
from
ProductChildCTE
inner join ProductLink on ProductChildCTE.ChildProductId = ProductLink.ParentProductId
)
select #ChildExists = 1 from ProductChildCTE where ChildProductId = #ChildProductId;
return #ChildExists;
end
When someone tries to insert a record into ProductLink, you could use a test like this to determine whether the proposed parent and child are already in the table as child and parent, respectively, and disallow the insertion if so.
This was just a quick write-up to illustrate one possible approach; I should mention that I don't know how well the performance of this thing will scale as the table gets larger. Hopefully it will suffice for your case. If not, let me know how to improve it.

Orders and Order Details

I am Business Logic component to enable Customers can place online orders. So far my simplified business logic look like this:
public class Product
{
public int productID { get; }
public string name { get; set; }
//other properties here like address and such
}
public class Order
{
public int orderID { get; }
public Customer customer { get; set; }
public List<Product> OrderItems { get; set; }
//other properties go here
}
List of Products will not support orders that contain products of multiple quantities. How do I add that support here? How would I call it from client side?
Another approach would be to add a level of indirection with an OrderItem class:
public class Product
{
public int productID { get; }
public string name { get; set; }
}
public class OrderItem
{
public Product product { get; set; }
public int quantity { get; set; }
}
public class Order
{
public int orderID { get; }
public Customer customer { get; set; }
public List<OrderItem> items { get; set; }
}
I.e. Order now refers to a list of OrderItems where each OrderItem has an associated quantity.
Don't use a List, use a Dictionary<Product,int>, where the int parameter is the quantity, or Dictionary<int,int>, where the first int is the product id and the second is the quantity.
You can always override .Equals for your Product class to be implemented in terms of your product id, so you're still using an int to define a product, but it may make things a bit simpler down the road (or if you ever need to change that).
I would add a third data object that contains order items that contains a link back to a product. The reason being is that you right now need quantity, but later I am going to guess you will want to give discounts on large where you might adjust the price per item down:
public class OrderLineItem
{
Product p { get; set; }
int Quantity {get; set;}
Decimal PricePerItem {get; set;}
}
You could make it something like
class OrderItem {
public Product Product ..
public int Qty ..
}
class Order {
public List<OrderItem> Items ..
}
You could structure it how you would envision a shopping cart to look. A single line would be a quantity of a certain product. Something like a ProductLine object which referenced a product and a quantity. Depending on how specific you logic is you may have additional attributes on a product such as manufacturer, SKU, etc. Sometimes you may get a comparable product from multiple manufacturers and for the sake of the order aren't interested but need to track that.
Please clarify:
1) In Class Order did you mean to write:
public List<Product> OrderItems() { get; set; }
//other properties go here
2) Are you sure you are not missing an intermediate object:
public class OrderItem
{
public int productID { get; }
public int quantity { get; set; }
// possibly other properties
}
In which case you would have:
public List<OrderItem> OrderItems() { get; set; }
3) Are you trying to ensure that each OrderItem has a quantity of One? In other words you do not want to allow people to order more than one of each product? Or are you trying to make sure that someone doesn't add the same product twice to the OrderItems?

Categories