Giter Site home page Giter Site logo

Comments (5)

ardalis avatar ardalis commented on May 23, 2024

It's not advisable typically to try to combine specifications. That moves the logic of composing the query out of the specification (and domain model) and into the calling code (probably in another less testable part of the app).

In your case why not have one that takes in a status and an id in its constructor?

from specification.

diegomodolo avatar diegomodolo commented on May 23, 2024

In my case, I would have a method at my service like GetOpenOrdersByCustomer, and I would only use the specifications inside my method, I would not make the specs visible to the UI, for example.
I was trying to achieve the concat so that I wouldn't need to create one spec for Status, one for Customer, and one for both.

from specification.

ardalis avatar ardalis commented on May 23, 2024

Again, we don't have plans to add support for combining specs. Personally I would create 3 specs and if there were logic between them that you really didn't want to duplicate, I'd do something like reference the expression in question from a shared constant value. But more likely I would just create 3 independent specs. If I really wanted one super-flexible spec, I'd create one that took in Customer and Status, but allowed for either one (but not both) of them to be omitted. That, too, seems kind of a poor design, so again I'd probably go the 3 spec route. Sorry to not be more help.

from specification.

diegomodolo avatar diegomodolo commented on May 23, 2024

I understand, and I thank you for all the info you've provided me.

from specification.

codelovercc avatar codelovercc commented on May 23, 2024

I think I just did this. If there is any problem with this design, please let me know, this is a copy of my work.

using Ardalis.Specification;

namespace Domain.Abstraction.Specifications;

/// <summary>
/// Domain Specification interface
/// </summary>
/// <typeparam name="T">The type being queried against.</typeparam>
/// <remarks>You have to call <see cref="Build"/> method to build the query logic before using.</remarks>
public interface IDomainSpecification<T> : ISpecification<T>
{
    /// <summary>
    /// Whether the current query model is an unconditional query model
    /// </summary>
    /// <returns><see langword="true"/> if it's an unconditional query model, otherwise <see langword="false"/></returns>
    bool IsPredicateLess() =>  !WhereExpressions.Any();

    /// <summary>
    /// build the query logic
    /// </summary>
    /// <remarks>In the case of multiple inheritance, the subclass must ensure that the implementation of the parent class is called in this method. 
    /// The order of calling the implementation of the parent class is determined according to the situation, and it is not necessary to call the implementation of the parent class first.Although the order in which query conventions are 
    /// constructed is not important it does not preclude the order being considered necessary in the new Ardalis.Specification package. 
    /// Under normal circumstances, the implementation of the parent class is called at the end, so that the query logic of the subclass will be constructed first</remarks>
    void Build();
}

/// <summary>
/// Pagination specification
/// </summary>
/// <typeparam name="T">The type being queried against.</typeparam>
/// <remarks>You have to call <see cref="Build"/> method to build the query logic before using.</remarks>
public interface IPaginationSpecification<T> : IDomainSpecification<T>
{
}


public class CompanySpec : Specification<Company> , IDomainSpecification<Company>
{
    private bool built;

    public void Build()
    {
       // make sure it only build once.
        if(built)
            return;
        //Do something before sub class build
        PreBuild();
        //Do something after sub class build
        built = true;
    }

    /// <summary>
    /// build query
    /// </summary>
    /// <remarks>make sure the implements are call the base <see cref="PreBuild"/>method</remarks>
    protected virtual void PreBuild()
    {
        Query.Where(e => !e.Deleted);
    }
}

public class CompanyPaginationSpec : CompanySpec, IPaginationSpecification<Company>
{
    ///<summary>
    /// Page index begin with 1
    ///</summary>
    public int PageIndex { get; }
    public int PageSize { get; }

    public CompanyPaginationSpec(int pageIndex, int pageSize)
    {
        PageIndex = pageIndex;
        PageSize = pageSize;
    }

    protected override void PreBuild()
    {
        base.PreBuild();
        Query.Skip(PageSize * (PageIndex - 1)).Take(PageSize);
    }
}

CompanySpec is an example class, you can create a common abstract class, it build the all the base entity or DTO query logic. the real entity or DTO implement this abstract class gets the base query logic.
I do not like call virtual method in the constructor, this may cause NullReferenceException. call virtual method in constructor need to make sure the sub class is not access its instance member in the override method.

@diegomodolo example updated.

from specification.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.