-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow combination of Specification with different projections #389
Comments
Hi @gabrielheming, We already support projections in the specs, you have to inherit from // Projecting directly to response DTOs. In addition the response is paginated and wrapped in PagedResponse<T>.
app.MapGet("/customers", async (IReadRepository<Customer> repo,
[AsParameters] CustomerFilter filter,
CancellationToken cancellationToken) =>
{
var spec = new CustomerSpec(filter);
var result = await repo.ProjectToListAsync<CustomerDto>(spec, filter, cancellationToken);
return Results.Ok(result);
}); |
Btw, if you prefer doing the mapping manually, then you may create a spec extension for common criteria and create projection specification per result type. So, in this case, the projection specs will act as mappers (since you're doing it manually). public static class CustomerSpecExtensions
{
public static ISpecificationBuilder<Customer> ApplyCommon(this ISpecificationBuilder<Customer> builder)
{
// Apply your common queries for Customer here
builder.OrderBy(x => x.Name);
return builder;
}
}
public class CustomerDtoSpec : Specification<Customer, CustomerDto>
{
public CustomerDtoSpec()
{
Query.ApplyCommon();
Query.Select(x => new CustomerDto(
x.Id,
x.Name,
x.Age,
x.Addresses.Select(a => new AddressDto(a.Id, a.Street, a.CustomerId)).ToList()));
}
} |
Hi @fiseni, thank you for your feedback.
I thought it was clear that I was already using it, and it led to the creation of the My point is a similar approach to your example from sample3 without having to rely on an external library and using only the Specification library. That is the general question that I will rephrase: Do you think it might be useful for the community as a implementation or do you rather not have such implementation on the package? Your example with On my take, I didn't want to add more methods on the already existing Thanks again for your feedback, it gave me more approaches to check on. |
@gabrielheming @ardalis ISpecification<Customer> spec = new CustomerSpec();
ISpecification<Customer, CustomerDto> projectionSpec = new CustomerDtoSpec();
// Get a new spec by combining the state from the base spec.
var newSpec = projectionSpec.Combine(spec); If we put it this way, then it's clear that we're trying to implement composite specifications. There have been thorough discussions on this topic, about the pros and cons of the composite specs. So, if we want to implement this feature then it should be done a bit more carefully and considering the broader scope, not just this specific case. Perhaps it's time we re-evaluate composite specs and the best way to move forward in that regard. |
True, and I agree with you. On my scenario, I've used a new type to take advantage of source generator as it specifies that the direction will be from Nevertheless, I would argue that the specification composition should be strict for the criteria, while projection an extension on top of the specification. Furthermore, I agree with you that discussing composition in details could be the proper approach. |
Ok, we'll plan this. But, before starting this work, we need substantial refactoring of the internals. It's something I've been planning for quite some time. Only then, we can start implementing this feature. |
Hello there,
I am using the Specification in a few projects that I am working on, and one of my projects came to the point that it has multiple Specifications only to represent different projections, using the same Where/Order expressions and/or Search Criteria.
This project in question is a WebAPI without any UI. At this moment, I am tweaking the current approach to map domain entities to their endpoints (VMs/DTOs). As some particular entities are loaded in different scenarios with partial data, we decided to map directly on the projection instead of loading the entity to memory and then mapping it to its VM/DTO.
My questioning came to the point that if I have to create a Specification per mapping/projection, is it still an advantage over the direct usage of DBContext? Of course, I am exaggerating it here, but it is only to make my point.
As Specification is easy to extend (extra points for you guys) I have created an extension method to combine a Specification with different projections.
My take on it is understanding whether it is useful/helpful or if it's just a load of BS making the purpose of Specification nonexistent.
In a nutshell, I created the
IProjectionSpecification
interface as below:And being able to use the extension method
.ToProjection
.I don't think it's necessary to go into implementation details right now, but I'm interested in hearing your thoughts.
If you believe it would be useful, I can submit it as a pull request or create an extension package.
The text was updated successfully, but these errors were encountered: