How to limit the number of query classes in CQRS? - c#

I am implementing CQRS and I am a little confused on the how quickly number of queries are getting.
I have googled it too but due to variety of flavors of CQRS I am not getting any appropriate solution. Perhaps I'm doing something wrong here? Here's my code and respective queries.
class User {
public int Id { get; set; }
public string Username { get; set; }
public string Status { get; set; }
public string Role { get; set; }
// ...
}
And I want to find user by its username, so I have written query for it
abstract class Query<TResult> { }
class FindUserByStatusQuery : Query<IEnumerable<User>> {
public string Status;
}
and the respective handler for it
interface IQueryHandler<TQuery, TResult> where TQuery : Query<TResult>
{
TResult Handle(TQuery query);
}
class FindUserByStatusQueryHandler : IQueryHandler<FindUserByStatusQuery, IEnumerable<User>>
{
public IEnumerable<User> Handle(FindUsersByAcountStatusQuery query)
{
using (Entities db = new Entities())
{
status = query.status.ConvertToString();
return db.Users.Where(u => u.Status.Contains(status)).ToArray();
}
}
}
Now, I want to look-up user by other fields too like by Id or by multiple fields (by both status & role). And there could be more queries like that.
My question is do I need to create separate query classes for them? Wouldn't that make number of queries quite high? How can I limit that?

I find the best approach is to be pragmatic - make the query fit the context of the current situation, and dont think beyond that.
You say they could query by status and role at the same time, so include both of those properties on the query object.
If you reuse the query 'somewhere else' in the domain, and it needs further search criteria, create a new query specifically for that domain problem.
Free yourself from the burden of 'limiting code' and deal with each situation separately. Creating objects that deal with multiple domain scenarios leads to complexity, regression issues and brittle classes.
Give your types a single responsibility

Related

Avoiding too many query types and mutations representing them in a single class - Hot Chocolate 13.2 (GraphQL)

We are building a GraphQL server using Hot Chocolate 13.2. Our application has a very common scenario with a Code-First approach and a SQL Server database. Operations are 100% destined for CRUD, and, for each model that we have on the application there is a DbSet in a single context.
public DbSet<Currency> Currencies { get; set; }
public DbSet<Language> Languages { get; set; }
// Too many another contexts.
Since there is an expressive quantity of models, the number of mutations and query types on the code is growing too much. Furthermore, the process for creating new mutations are basically a copy/paste, so we started having too many classes doing exactly the same thing (except by the Type that changes for each class).
The problem:
From what we know, Hot Chocolate does not allow different Query and Mutations types being exposed with the same method name across these classes, that's why we cannot use Generic Methods. Example:
public class BaseMutation<T> : Validator where T : BaseEntity
{
public static T Add([Service]MyDbContext context, ClaimsPrincipal claims, [Argument]T model)
{
// Do some stuff
context.Set<T>().Add(model);
context.SaveChanges();
}
}
Our question:
Does anyone know a way to represent different query and mutation types in a single class? Or even, to create a unique class for Query Type objects and another class for the Mutation Types, with the possibility of having a on the calls?
By the way, I found an class attribute called "GraphQLName", that permits us for changing the operation name.
Is there any way for dynamically change this value to represent all these queries and mutations in a single class?
[GraphQLName("dynamic-name")]
public static T <DYNAME_METHOD_NAME>([Service]MyContext context, ClaimsPrincipal claims, [Argument] T model)
{
// Do some stuff
context.Set<T>().Add(model);
context.SaveChanges();
}
You could use the fluent API and write extension methods on top of it.
public class QueryType : ObjectType
{
protected override void Configure(IObjectTypeDescriptor descriptor)
{
descriptor.AddEntity<Foo>("foo");
descriptor.AddEntity<Bar>("bar");
}
}
public static class QueryExtensionMethods
{
public static IObjectTypeDescriptor AddEntity<T>(
this IObjectTypeDescriptor descriptor,
string name) where T: IHasId
{
descriptor.Field($"{name}ById")
.Argument("id", x => x.ID(typeof(T).Name))
.Resolve(x =>
{
var dbContext = x.Service<MyDbContext>();
var id = x.ArgumentValue<Guid>("id")
return dbContext.Set<T>().FirstOrDefault(x => x.Id == id);
})
.Type<ObjectType<T>>();
}
}
But, to also mention this here. This is not really GraphQL best practice. In GraphQL you should think beyond CURD an implement mutations and query in a way that you actually want them to be consumed, rather than exposing a generic solution.
you rather have mutations changeAddress or changeUserName rather than a combinded mutation updateUser

Proper aggregate design and complex specification query

I have a lack of understanding of the DDD aggregate topic.
I do have an Offer aggregate that has navigation property to its children's collection OfferProducts.
When I learned entity framework I thought I should always define navigation properties on both sides of the relation but Ardalis (maintainer of Specification package for ef https://github.com/ardalis/Specification) wrote somewhere these words which I do not understand correctly:
You want to avoid having navigation properties that span Aggregates.
So you need to decide where navigation properties should go, and where
non-navigation key properties should go instead.
This is how I designed my entities:
public class Offer : BaseEntity, IAggregateRoot
{
...
public ICollection<OfferProduct> OfferProducts { get; private set; } = new List<OfferProduct>();
public Guid InquiryId { get; private set; }
public virtual Inquiry Inquiry { get; private set; } = default!;
}
public class OfferProduct : BaseEntity, IAggregateRoot
{
...
public Guid OfferId { get; private set; }
public virtual Offer Offer { get; private set; } = default!;
public Guid InquiryProductId { get; private set; }
public virtual InquiryProduct InquiryProduct { get; private set; } = default!;
}
public class Inquiry : BaseEntity, IAggregateRoot
{
...
public ICollection<Offer> Offers { get; private set; } = new List<Offer>();
public ICollection<InquiryProduct> Products { get; private set; } = new List<InquiryProduct>();
}
public class InquiryProduct : BaseEntity, IAggregateRoot
{
...
public Guid InquiryId { get; private set; }
public virtual Inquiry Inquiry { get; private set; } = default!;
public ICollection<OfferProduct> OfferProducts { get; private set; } = new List<OfferProduct>();
}
Ardalis is saying that navigation properties should be defined only on one side.
I do not know if it is because of some DDD principles or maybe because it has some performance drawbacks?
Repository from your Ardalis specification package only works with aggregate root.
OfferProduct entities are created only with the Offer entity and are never updated.
InquiryProduct entities are created only with the Inquiry entity and are never updated.
I have a business use case where I need to fetch OfferProducts not only belonging to one Offer but filtered by InquiryProductId so I thought the easiest way will be to mark the OfferProduct entity with IAggregateRoot interface and query it from the repository directly. But I think it's cheating and it's not correct because if I understand correctly AggregateRoot should be the only one and I should always query from the root.
I could fetch it from the Inquiry aggregate root but then my specification would have to be that complex:
public class InquiryProductOffersSpec : Specification<Inquiry, InquiryDetailsDto>, ISingleResultSpecification
{
public InquiryProductOffersSpec(Guid inquiryId, Guid productId) =>
Query
.Where(i => i.Id == inquiryId)
.Include(i => i.Products.Where(ip => ip.Id == productId))
.ThenInclude(ip => ip.OfferProducts);
}
This probably would be more correct from the DDD perspective but the query will be less performant than simple select * from OfferProducts where inquiryProductId = 'someId'
So my questions are:
should I remove IAggregateRoot from InquiryProduct and OfferProduct entities and fetch only from the Inquiry entity?
why it is better to keep navigation properties only on one side of the relation?
maybe my entities and relations are designed incorrectly and that's why I am struggling with that complex query?
I will introduce the operation of the system:
The system can create inquiries with its InquiryProducts, then there can be offers created for each inquiry and each offer can have some OfferProducts related to the InquiryProduct.
When writing it thought came to my mind that maybe the only AggregateRoot should be the Inquiry entity as any of the other entities can't exist without Inquiry. But In the system, I also need to fetch(search) offers independently of inquiry and I couldn't do it if I won't mark Offer with an IAggregateRoot interface.
should I remove IAggregateRoot from InquiryProduct and OfferProduct entities and fetch only from the Inquiry entity?
Yes. The whole point of an aggregate root is to organize entities into top-level entities responsible for their dependents which don't really make sense to query on their own.
why it is better to keep navigation properties only on one side of the relation?
Bi-directional references should only be used when there is a clear benefit to having them. Otherwise they just lead to having multiple pathways to get to information that can either result in expensive, unexpected lazy load calls or "broken" links if Lazy Loading is disabled.
For example, a relationship between something like a Customer and Order can make sense to treat both as aggregate roots. There will be a arguable value to get information about Orders for a particular customer, and value in getting information about a Customer from a given Order. Versus scenarios like relationships like Orders and Users (Created By/Modified By) or Orders/Customers and Addresses. An Order benefits from being able to access information about a User that created or last modified it, or Address details, but it doesn't make much sense to bother tracking what Orders a user Created/Modified, or what Order a given Address might be associated with.
You can still query this information if needed through the aggregate root without relying on bi-directional references. For instance if I do happen to care about what orders a particular user did modify, I don't need the structural overhead and "mess" of:
var orders = currentUser.OrdersICreated;
// or
var orders = currentUser.OrdersIModified;
Since most entities in a system might track something like a CreatedBy/ModifiedBy reference back to a User, it would be ridiculous to start putting bi-directional references to every collection of entities in the User entity.
Where these aren't bi-directional references... I can instead use the aggregate root if and when there is a need:
var ordersQuery = _context.Orders.Where(x => x.CreatedBy.UserId == currentUserId);
The problem with relying on bi-directional references is that you end up doing a lot of processing in-memory, which is expensive from a memory standpoint, as well as you end up dealing with potentially stale data over time. In the above example, going back to build queries rather than relying on navigation properties means that I can leverage projection to get back just the details I might need, which could be something as simple as a .Any() check or a .Count().
My advice when it comes to getting the most out of EF is to adapt to leverage its querying and projection to build efficient queries, then deal with aggregate roots solely when you actually need to work with a complete picture of ideally a single entity and it's related details.

How many GET methods a service should have?

What are the best practices for writing a service layer methods that retrieves data from repository?
Let's say we have two models: Team and User (user is part of a team):
public class User {
public int Id { get; set; }
public string Name { get; set; }
public int TeamId { get; set; }
public virtual Team Team { get; set; }
public bool Active { get; set; }
}
public class Team {
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
If I want to write service to retrieve user data from repository by various conditions, do I have to write multiple methods to get a user e.g. getAll, getAllByName, getAllActiveByName, getAllActiveByTeamId, getAllActiveByNameAndTeamId, etc?
public IEnumerable<User> GetAll()
{
return _repository.GetAll();
}
public IEnumerable<User> GetAllActiveByName(string name)
{
return _repository.GetBy(u => u.Name == name && u.Active);
}
public IEnumerable<User> GetAllActiveByNameAndTeamId(string name, int teamId)
{
return _repository.GetBy(u => u.Name == name && u.Active && u.TeamId == teamId);
}
These are just simple examples but in real life we can end up having tens of service methods for different scenarios, when models are more complex.
Or maybe it is better to have one GetBy method that will return users based on the provided filter? I use Generic Repository Pattern and I could use GetBy method when implementing GetBy service method:
public IEnumerable<User> GetBy(Expression<Func<User, object>>filter )
{
return _usersRepository.GetBy(filter);
}
Having this I would not have to write tens of "duplicated" methods for all the scenarios.
Then it would be controller responsibility to set the filter:
public ViewResult Index(int teamId = 0){
//[...]
var users = _usersService.GetBy(u => u.IsActive && u.teamId == teamId);
//[...]
}
Any thoughts on that?
I'm of the opinion that you should have as many query methods as you have scenarios.
In that way you can optimize individual queries by for example using a precalculated view.
Some of your queries might use eager loading, other might use lazy loading...
Also, if you always return IQueryable how are you going to test it? Your service will have only one method GetAll and is so anemic that you can just get rid of it and use repository directly in the controller.
Another argument against GetAll is that any one can execute any query in the UI!
Consider reading about CQRS.
Or maybe it is better to have one getAll method that will return only
active users and then use lambda expression in the controller?
No. This kind of query will be good only for static data that too in-memory. Say you have some application level data and it is not going to change for certain time, then instead of querying it everytime, you getall for first time and then put in local server cache. Then use it for next simultaneous requests. But this approach is not going to for heavily changing dynamic data. Also performance of this query depends on number of records it is returning, so sometimes it might give very bad performance.
do I have to write multiple methods to get a user e.g. getAll,
getAllByName, getAllActiveByName, getAllActiveByTeamId,
getAllActiveByNameAndTeamId, etc?
Thats better. This approach will give you load on demand freedom, that means load necessary data when it is required, instead of getting all data and discarding it.

Rich domain model with behaviours and ORM

After watching NDC12 presentation "Crafting Wicked Domain Models" from Jimmy Bogard (http://ndcoslo.oktaset.com/Agenda), I was wandering how to persist that kind of domain model.
This is sample class from presentation:
public class Member
{
List<Offer> _offers;
public Member(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
_offers = new List<Offer>();
}
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<Offer> AssignedOffers {
get { return _offers; }
}
public int NumberOfOffers { get; private set; }
public Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc)
{
var value = valueCalc.CalculateValue(this, offerType);
var expiration = offerType.CalculateExpiration();
var offer = new Offer(this, offerType, expiration, value);
_offers.Add(offer);
NumberOfOffers++;
return offer;
}
}
so there are some rules contained in this domain model:
- Member must have first and last name
- Number of offers can't be changed outside
- Member is responsible for creating new offer, calculating its value and assignment
If if try to map this to some ORM like Entity Framework or NHibernate, it will not work.
So, what's best approach for mapping this kind of model to database with ORM?
For example, how do I load AssignedOffers from DB if there's no setter?
Only thing that does make sense for me is using command/query architecture: queries are always done with DTO as result, not domain entities, and commands are done on domain models. Also, event sourcing is perfect fit for behaviours on domain model. But this kind of CQS architecture isn't maybe suitable for every project, specially brownfield. Or not?
I'm aware of similar questions here, but couldn't find concrete example and solution.
This is actually a very good question and something I have contemplated. It is potentially difficult to create proper domain objects that are fully encapsulated (i.e. no property setters) and use an ORM to build the domain objects directly.
In my experience there are 3 ways of solving this issue:
As already mention by Luka, NHibernate supports mapping to private fields, rather than property setters.
If using EF (which I don't think supports the above) you could use the memento pattern to restore state to your domain objects. e.g. you use entity framework to populate 'memento' objects which your domain entities accept to set their private fields.
As you have pointed out, using CQRS with event sourcing eliminates this problem. This is my preferred method of crafting perfectly encapsulated domain objects, that also have all the added benefits of event sourcing.
Old thread. But there's a more recent post (late 2014) by Vaughn Vernon that addresses just this scenario, with particular reference to Entity Framework. Given that I somehow struggled to find such information, maybe it can be helpful to post it here as well.
Basically the post advocates for the Product domain (aggregate) object to wrap the ProductState EF POCO data object for what concerns the "data bag" side of things. Of course the domain object would still add all its rich domain behaviour through domain-specific methods/accessors, but it would resort to inner data object when it has to get/set its properties.
Copying snippet straight from post:
public class Product
{
public Product(
TenantId tenantId,
ProductId productId,
ProductOwnerId productOwnerId,
string name,
string description)
{
State = new ProductState();
State.ProductKey = tenantId.Id + ":" + productId.Id;
State.ProductOwnerId = productOwnerId;
State.Name = name;
State.Description = description;
State.BacklogItems = new List<ProductBacklogItem>();
}
internal Product(ProductState state)
{
State = state;
}
//...
private readonly ProductState State;
}
public class ProductState
{
[Key]
public string ProductKey { get; set; }
public ProductOwnerId ProductOwnerId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<ProductBacklogItemState> BacklogItems { get; set; }
...
}
Repository would use internal constructor in order to instantiate (load) an entity instance from its DB-persisted version.
The one bit I can add myself, is that probably Product domain object should be dirtied with one more accessor just for the purpose of persistence through EF: in the same was as new Product(productState) allows a domain entity to be loaded from database, the opposite way should be allowed through something like:
public class Product
{
// ...
internal ProductState State
{
get
{
// return this.State as is, if you trust the caller (repository),
// or deep clone it and return it
}
}
}
// inside repository.Add(Product product):
dbContext.Add(product.State);
For AssignedOffers : if you look at the code you'll see that AssignedOffers returns value from a field. NHibernate can populate that field like this: Map(x => x.AssignedOffers).Access.Field().
Agree with using CQS.
When doing DDD first thing, you ignore the persistence concerns. THe ORM is tighlty coupled to a RDBMS so it's a persistence concern.
An ORM models persistence structure NOT the domain. Basically the repository must 'convert' the received Aggregate Root to one or many persistence entities. The Bounded Context matters a lot since the Aggregate Root changes according to what are you trying to accomplish as well.
Let's say you want to save the Member in the context of a new offer assigned. Then you'll have something like this (of course this is only one possible scenario)
public interface IAssignOffer
{
int OwnerId {get;}
Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc);
IEnumerable<Offer> NewOffers {get; }
}
public class Member:IAssignOffer
{
/* implementation */
}
public interface IDomainRepository
{
void Save(IAssignOffer member);
}
Next the repo will get only the data required in order to change the NH entities and that's all.
About EVent Sourcing, I think that you have to see if it fits your domain and I don't see any problem with using Event Sourcing only for storing domain Aggregate Roots while the rest (mainly infrastructure) can be stored in the ordinary way (relational tables). I think CQRS gives you great flexibility in this matter.

Wrapping DbSet<TEntity> with a custom DbSet/IDbSet?

First off, I think this is somewhat ridiculous to do but the other members of my team insist upon it and I can't come up with a good argument against it other than "I think it's dumb"...
What we're trying to do is create a completely abstract data layer and then have various implementations of that data layer. Simple enough, right? Enter Entity Framework 4.1...
Our end goal here is that the programmers (I do my best to stay only on the data layer) never want to have to be exposed to the concrete classes. They only ever want to have to use interfaces in their code, aside from obviously needing to instantiate the factory.
I want to achieve something like the following:
First we have our "Common" library of all of the interfaces, we'll call it "Common.Data":
public interface IEntity
{
int ID { get; set; }
}
public interface IUser : IEntity
{
int AccountID { get; set; }
string Username { get; set; }
string EmailAddress { get; set; }
IAccount Account { get; set; }
}
public interface IAccount : IEntity
{
string FirstName { get; set; }
string LastName { get; set; }
DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
}
public interface IEntityFactory
{
DbSet<IUser> Users { get; }
DbSet<IAccount> Accounts { get; }
}
From that we then have an implementation library, we'll call it "Something.Data.Imp":
internal class User : IUser
{
public int ID { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public IAccount Account { get; set; }
public class Configuration : EntityTypeConfiguration<User>
{
public Configuration() : base()
{
...
}
}
}
internal class Account : IAccount
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
public class Configuration : EntityTypeConfiguration<Account>
{
public Configuration() : base()
{
...
}
}
}
Factory:
public class ImplEntityFactory : IEntityFactory
{
private ImplEntityFactory(string connectionString)
{
this.dataContext = new MyEfDbContext(connectionString);
}
private MyEfDbContext dataContext;
public static ImplEntityFactory Instance(string connectionString)
{
if(ImplEntityFactory._instance == null)
ImplEntityFactory._instance = new ImplEntityFactory(connectionString);
return ImplEntityFactory._instance;
}
private static ImplEntityFactory _instance;
public DbSet<IUser> Users // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Users; }
}
public DbSet<IAccount> Accounts // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Accounts; }
}
}
Context:
public class MyEfDataContext : DbContext
{
public MyEfDataContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer<MyEfDataContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new User.Configuration());
modelBuilder.Configurations.Add(new Account.Configuration());
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
}
Then the front-end programmers would be using it such as:
public class UsingIt
{
public static void Main(string[] args)
{
IEntityFactory factory = new ImplEntityFactory("SQLConnectionString");
IUser user = factory.Users.Find(5);
IAccount usersAccount = user.Account;
IAccount account = factory.Accounts.Find(3);
Console.Write(account.Users.Count());
}
}
So that's pretty much it... I'm hoping someone on here might be able to either point me in the right direction or help me out with a good argument that I can fire back at the development team. I've looked at some other articles on this site about EF not being able to work with interfaces and one reply saying that you can't implement IDbSet (which I find kind of curious, why would they provide it if you couldn't implement it?) but so far to no avail.
Thanks in advance for any help!
J
The first argument is that EF doesn't work with interfaces. DbSet must be defined with a real entity implementation.
The second argument is that your entities should not contain DbSet - that is context related class and your entities should be pure of such dependency unless you are going to implement Active record pattern. Even in such case you will definitely not have access to DbSet of different entity in another entity. Even if you wrap set you are still too close to EF and entity never have property accessing all entities of another entity type (not only those related to current instance).
Just to make it clear DbSet in EF has very special meaning - it is not a collection. It is entry point to database (for example each LINQ query on DbSet hits database) and it is in normal scenarios not exposed on entities.
The third argument is that you are using a single context per application - you have a single private instance per singleton factory. Unless you are doing some single run batch application it is definitely wrong.
The last argument is simply practical. You are paid for delivering features not for wasting time on abstraction which doesn't give you (and your customer) any business value. It is not about proving why you should not create this abstraction. It is about proving why you should do it. What value will you get from using it? If your colleagues are not able to come with arguments which have business value you can simply go to your product manager and let him use his power - he holds the budget.
Generally abstraction is part of well designed object oriented application - that is correct. BUT:
Every abstraction will make your application somehow more complex and it will increase cost and time of development
Not every abstraction will make your application better or more maintainable - too much abstraction has reverse effect
Abstracting EF is hard. Saying that you will abstract data access in the way that you can replace it with another implementation is task for data access gurus. First of all you must have very good experience with many data access technologies to be able to define such abstraction which will work with all of them (and in the end you can only tell that your abstraction works with technologies you thought about when you design that). Your abstraction will work only with EF DbContext API and with nothing else because it is not an abstraction. If you want to build universal abstraction you should start studying Repository pattern, Unit of Work pattern and Specification pattern - but that is a big deal of work to make them and to implement them universal. The first step needed is to hide everything related to data access behind that abstraction - including LINQ!
Abstracting data access to support multiple APIs make sense only if you need it now. If you only think that it can be useful in future than it is in business driven projects completely wrong decision and developer who came with that idea is not competent to make business targeting decisions.
When it make sense to do "a lot of" abstraction?
You have such requirement now - that moves burden of such decision to person responsible for budget / project scope / requirements etc.
You need abstraction now to simplify design or solve some a problem
You are doing open source or hobby project and you are not driven by business needs but by purity and quality of your project
You are working on platform (long living retail product which will live for a long time) or public framework - this generally returns to the first point because this type of products usually have such abstraction as requirement
If you are working only targeted application (mostly single purpose applications on demand or outsourced solutions) the abstraction should be used only if necessary. These applications are driven by costs - the target is delivering working solution for minimal costs and in the shortest time. This target must be achieved even if resulting application will not be very good internally - the only thing which matters is if application meets requirements. Any abstraction based on "what if ... happens" or "perhaps we will need ..." increases costs by virtual (non existing) requirements which will in 99% never happen and in most cases initial contract with customer didn't count which such additional costs.
Btw. this type of applications is targeted by MS APIs and designer strategy - MS will make a lot of designers and code generators which will create non optimal but cheap and quick solutions which can be created by people with smaller skill set and are very cheap. The last example is LightSwitch.

Categories

Resources