1

I am trying to learn CQRS in my spare time. Say I have a class like this:

public class Person
{
  private Guid Id {get; set;}
  private Guid Name {get; set;}
  private List<Order> orders;

  //Methods and constructor go here

}

I am thinking of a scenario where it would be beneficial to persist the Person class to the write database (SQL Server) and then the person and order class to the read database (Mongodb).

The only reason I need to persist the Person class on the write side is to benefit from change tracking.

Is it normal for the write database to have different fields to the read database i.e. in this case orders are not persisted on the write side. Or should the same classes and fields be persisted on both sides?

I realise that relational databases are different to NoSQL databases and both have their benefits and limitrations. I am specifically asking if it is normal for information to be available in the read database that is not available in the write database.

I realise the answer to my question is yes; from a technical point of view. I am asking when thinking about the principle of least astonishment.

Update 20/01/19

Here is a sample of code from the write side domain model:

 public class Product
    {
        public Guid Id { get; set; }
        public string Code { get; set; }
        public string Description { get; set; }

        public void LookupDescriptionByCode(List<ProductDescriptionLookup> productCodes)
        {
            Description = productCodes.Find(x => x.Code == Code).Description;
        }
    }

    public class ProductDescriptionLookup
    {
        public Guid Id { get; set; }
        public string Code { get; set; }
        public string Description { get; set; }
    }

The database (lookup tables) looks like this:

create table ProductDescriptionLookup(Id uniqueidentifier, Code varchar(100), Description varchar(100))
insert into ProductDescriptionLookup (Id,Code,[Description])
values (newid(), 'prod1','Product1')

Here is some test code for the write side:

[Fact]
        public void Test()
        {
            List<ProductDescriptionLookup> list = new List<ProductDescriptionLookup>();
            list.Add(new ProductDescriptionLookup { Id = Guid.NewGuid(), Code=  "prod1", Description="Product1" });
            Product p1 = new Product { Id = Guid.NewGuid(), Code = "prod1", Description = "" };
            p1.LookupDescriptionByCode(list);
        }

Here is the read model (which is mapped to a MongoDB database):

public class Product
    {
        public Guid Id { get; set; }
        public string Description { get; set; }
     }

Notice that the Product Code is not even persisted to the read side. Therefore there is no need for the lookup table on the read side (because it will never have to lookup the description by product code). Therefore I am planning to exclude the ProductDescriptionLookup table from the read side. This works perfectly from a technical point of view, however I am wandering if it is frowned upon as the read database is now different to the write database.

w0051977
  • 7,031
  • 6
  • 59
  • 87

1 Answers1

2

Normally I would expect the changes you write to the Write side to eventually make their way over to the Read side.

With the same DB make and structure on both sides you can see how this is easily achieved with built in replication technologies. To the outside observer it looks like a single database, you are just cleverly optimising it.

If you used different databases for each side its unclear how you would sync the two up.

Additonally if one has extra information that the others structure doesn't have a place for. Then you cant both read and write that info without breaking the pattern. You would end up with two versions of your data and which one was authorative might become an open question.

As you say, techincally possible, but you would have to see the whole solution to see if it worked nicely and made an overall improvement.

Ewan
  • 70,664
  • 5
  • 76
  • 161
  • What about lookup tables? Say I want to lookup a value on the write side to report it to the read side I.e. the lookup table is not needed on the read side. I guess I can just exclude it - is that normal? Thanks. I will accept once I understand this. +1. – w0051977 Jan 18 '19 at 12:28
  • I dont understand what you mean. Normally the databases should have identical structure. I think its accepted that some commands will read from the write side as part of their function. – Ewan Jan 18 '19 at 17:49
  • Thanks. I am saying that the lookup table is only needed on the write side because the read side will only display the value that was looked up. Therefore I am asking if it is normal for a lookup table to exist on the write side (SQL Server) but not on the read side (MongoDB). If that still does not make sense then let me know and I will post some code. When I say lookup tables I mean this: https://softwareengineering.stackexchange.com/questions/300992/lookup-tables-are-they-a-leak-in-the-domain-model – w0051977 Jan 20 '19 at 13:00
  • nope, dont understand – Ewan Jan 20 '19 at 13:23
  • Thanks. I have added code to my question in a last attempt to explain my question. Could you review it? – w0051977 Jan 20 '19 at 16:45
  • sorry it makes no sense to me. why doesnt your read model have a product code? – Ewan Jan 20 '19 at 16:57
  • The write side has to connect to APIs, which return a product code only. I then resolve the product code to a product description, which is more user friendly for the end user. – w0051977 Jan 20 '19 at 17:15
  • No, i think your setup is wrong. add a productCode table and have it on both sides – Ewan Jan 20 '19 at 17:37
  • Thanks. Could you explain why? The product Code is already available on the read side. – w0051977 Jan 20 '19 at 17:53
  • its not part of product – Ewan Jan 20 '19 at 18:22
  • But it is not needed on the read side. That is my point. – w0051977 Jan 20 '19 at 18:46
  • its needed on the write side too. otherwise how do you populate it – Ewan Jan 20 '19 at 19:19
  • It is populated by the write side before it reaches the read side I.e. notice that there is no product code on the read side. – w0051977 Jan 20 '19 at 20:42