I'm wondering if there is a common solution/pattern for the following situation:
Let's say I have a webshop application. There you can create orders, which consists of items. Each order item can have one or more files as attachments. (May not make sense, but it's just an example). Pseudocode:
Order
{
Guid Id
List<OrderItem> Items
}
OrderItem
{
Guid Id
List<Attachment> Attachments
}
Attachment
{
Guid Id
string Filename
byte[] Content
}
The technology is ASP.Net MVC + React. When creating an order, I cannot send the files in the same request due to request length limits. So I have to first send a request to create an order, and then send the files one by one. How do I get the correct OrderItem id (in frontend) for each attachment?
When creating an order, none of the items have ids. CreateOrder method returns the created order and items with ids, but how can I map items in the result to items in the request that don't have ids? Result items may even be sorted differently.
One option could be to add a separate id field to OrderItem dto, e.g. NewItemId. In that case, that id would be generated by the frontend and returned by the backend in the result. However, due to how the application is structured, that would require including the property in a domain class. Is there any more elegant solution?
Related
I'm following Domain Driven Design for this project.
I have got an object containing an image. Let's call it Product:
class Product {
UniqueID id;
ProductName name;
ImageBytes imageBytes;
}
UniqueID, ProductName and ImageBytes are just validated objects that represent respectively a String, a String and a List<int>.
I would like to store the actual image on Firebase Storage and saving the imageId on Firestore.
So, in my idea, I have an image on Firebase Storage with id xYF87Ejid0093RTcxaWpof and a Doc in the Firestore containing this id instead of the actual image.
The problem I'm stuck into is writing the Data Transfer Object of a Product. How should I convert an imageId into the actual image?
Please consider that I'm using DDD, so my DTO and my Entity classes are Unions (using Freezed).
I think I should have an intermediate class called FirestoreProduct at the Infrastructure level that looks like this:
class FirestoreProduct {
UniqueID id;
ProductName name;
UniqueID imageId;
}
So that I can write a DTO that uses this class instead and I can create the Product object from the repository class after I downloaded the image.
Is there any better way to solve this problem in the DDD way?
Thanks in advance.
Do you really need the ImageBytes to perform the business logic of your product entity? I even guess that your Product is an aggregate root and thus will have data and corresponding behaviour (business logic) in it.
So from my point-of-view the model of your FirestoreProduct is closer to a domain model than your Product class.
I consider your image a separate aggregate which can reside in the same service but a different storage or which could even live in a separate service.
Either way the Product aggregate should only need a reference to the image. I would model it somehow like this
class Product {
ProductId id;
ProductName name;
ImageId imageId;
}
whereas ProductId and ImageId would be value objects for strongly-typed ids.
I expect the storing/upload of a new image to be performed in a separate transaction than creating/updating a product itself. That means when you create a new product or perform some business logic on it to change it your image has already been uploaded to the Firestore and you only work with the image id in your product aggregate.
Your Product DTO (you could also call it view model) on the other hand which you use for providing data for the UI (i.e. for reading data) can look different then the Product aggregate. This is okay and also makes total sense.
So the DTO would look something like this instead:
class ProductDto {
UniqueID id;
ProductName name;
ImageBytes imageBytes;
}
Note: I don't know if ImageBytes is the right type for the DTO as my flutter knowledge is limited but I hope you get the idea.
With that you can bypass the Product aggregate domain repository completely and have another service class which will give you all the data you need for reading/viewing the Product data. As you do not change anything by reading data you do not go through your domain model and optimize for reads.
The code which than builds the DTO will go to your persistence for querying some Product data but also to Firebase for querying the actual image. You could even reload the actual Firebase image afterwards by a separate call from the UI if performance is an issue, for instance if you retrieve a whole list of product data for reading at once.
Supposing I have two tables Meetings and Attendees.
My database looks like this.
// Table Meeting
Id
Description
// other properties ...
// Attendee
Id
Name
MeetingId
// other properties ...
I have two views that are mapped to these tables. One is ViewMeetings with just the meeting data the other ViewMeetingAttendees joined with Attendees.
I want to use table per type(TPT), mapping each table to a view.
public abstract class MeetingBase
{
// Some properties here
}
public class ViewMeeting : MeetingBase
{
}
public class ViewMeetingAttendee : MeetingBase
{
public String AttendeeName { get;set; }
}
// Configuration
moduleBuilder.Entity<ViewMeeting>().ToTable("ViewMeetings");
moduleBuilder.Entity<ViewMeetingAttendee>().ToTable("ViewMeetingAttendees");
// NOTE fixed the ViewMeeting error as stated in HansVG answer below.
Every time I try to run this code I get an error Invalid Column Name "Discriminator"
I understand that the entity framework is trying to resolve the types as a table per hierarchy(TPH). However, I still want to map the properties using inheritance without the inferred TPH. This is reasonable since all the columns are the same except for one. I have ten other columns and two views. Also I have a single meeting entity needing most of the same columns for CRUD operations.
Is there a way to keep the inheritance but lose the discriminator error? [NotMapped] is not an option since I am still pulling the data from the database. Also, I don't prefer to join the tables locally using LINQ since there are joined entities that don't need to be mapped otherwise.
You defined 'ViewMeeting' twice and didn't configure 'ViewMeetingAttendee'.
Your configuration should be:
moduleBuilder.Entity<ViewMeeting>().ToTable("ViewMeetings");
moduleBuilder.Entity<ViewMeetingAttendee>().ToTable("ViewMeetingAttendees");
I have a Symfony 3.4 projet with a REST api. I use JMS serializer.
I have a entity User and I have a route /api/user which return the user id, name , ...
I also have a entity badges which has a relation many to many with user (so a user_badge table). Like I read, when the pivot table have extra column (like in my case on user_badge), I need to create two relation many to one to link my user to badges.
In my route /api/user I add the return on my badges with JMS, I return my badge id and the achievement date (the extra column) from user_badge with the method getUserBadges from my entity User.
But now I want to order by the badges using a column from the badge entity.
How can I achieve this ? The fact than my model user can't access the badges without a heavy foreach. I need to make a request to getting all the badges in the correct order and passing this to JMS.
(I don't know which source file I should provide, cause I don't really know how to achieve it)
Considering I have just one table named entity, it's a REST heresy to have an /entity URI to serve some fields of this table and another /entity/id/details path to share a complete, or more large, representation of them?
It depends on your requirement.
A good start could be exposing standard methods to the /entities resource,
and implementing the Partial Response pattern via ?fields property.
Example:
In the case of Entity fields being: id, name, description
/entities/{id}?fields=id,name
would return a resource containing id and name only
My overall goal is to be able to display all Customer Information in my CustomerController->Details View and have no idea how to pass all of this data:
Customer info - (fields directly in Customer table)
Customer contacts
Customer locations
Customer documents
I am able to display the customer info just fine because I am doing something like this and passing it to my view:
public ActionResult Details(int? id)
{
Model.Customer customer = _custService.GetCustByID(id);
return View(customer);
}
I have absolutely no idea how to go from just this which gives me access to direct Customer properties in my view to displaying all of these other lists of related customer items that come from separate tables.
Here are a few details on my project setup:
I am using EF6DbFirst and I also create a Dto for each one of my entities and use AutoMapper to map everything. My Customer.cs model has all of the customer's direct properties and also a couple that look like this for the things that are one-to-many relationships:
public List<CustomerContact> Contacts { get; set; }
Now in my AutoMapper config I did the following since my table is named CustomerContacts in EF:
CreateMap<Customer, Model.Customer>()
.ForMember(dest => dest.Contacts, opt => opt.MapFrom(src => src.CustomerContact));
CreateMap<Customer_GetAll_Result, Model.Customer>();
I am not sure if this is the proper way to do this with AutoMapper or if there is anything else I have to tell it when accessing other tables. I am thinking the only reason I have to map this property is because I want to change the name to just c.Contacts rather than c.CustomerContacts.
Side question:
As you can see I am also trying to map values that come from my GetAll stored procedure which my custService.GetAll() uses in my controller to bind a grid of customers. I don't think this matters in this case but I am assuming if I ever need to loop through that list that comes from the proc and get the contacts for each customer they will not be available since my stored proc only returns direct customer properties which is why I can't do the mapping for that one. Is there any workaround for this?