简体   繁体   中英

C# Domain Model + repository: Where to put code that loads an entity

I have a model class which is loaded from a "GetById" method in my repository class. I now need to add additional properties to this entity, which aren't saved in the database, but are calculated by a service class. Something like:

public class MyEntity
{
    public int ThingId { get; set; };
    public string ThingName { get; set; }

    // Set from the service
    public int WooFactor { get; set; }
}

public class WooFactorGenerator
{
    public int CalculateWooFactor(MyEntity thing); // Hits other services and repo's to eventually determine the woo factor.
}

// Code to get a "MyEntity":

var myEntity = repo.GetById(1);
var gen = new WooFactorGenerator();
myEntity.WooFactor = gen.CalculateWooFactor(myEntity);

So in order to load/saturate a MyEntity object, I need to load from the db, and then call the generator to determine the "woo factor" (ahem). Where should this code go from an architectural viewpoint? Current thoughts:

1) In the repository: I feel like I'm handing too much responsibility to the repo if I add it here.

2) In the "MyEntity" class. Add the code in here that perhaps lazy-loads the WooFactor when it is accessed. This would add a lot of dependencies to MyEntity.

3) A separate service class - seems overkill and un-necessary.

  • If WooFactor is purely dependent on MyEntity properties then it must be done inside MyEntity
  • If it requires external info (such as configuration, rules, etc) then it needs to be a separate service outside Repository . I would create a WooEntity here with this additional property.

In any case, it should never be in the Repository .

Google CQRS. What you need to do is to separate the read and write concerns. If the calculation is needed by something else other than the entity, you have your answer in plain sight.

I ran into similar concerns recently where I needed to aggregate different data to produce my entity. I eventually decided to create a service to handle the construction of my Entity and any actions that happened to the Entity

Using your example It might look like this:

public MyEntityService
{
  public MyEntity GetById(int id)
  {
    MyEntity myEntity = _repo.GetById(id);
    myEntity.WooFactor = _wooFactorGenerator.CalculateWooFactor(myEntity);
    return myEntity;
  }
}

In the end this worked out the best for the project as any interaction to the Entity was done via the service.

How you manage getting data from the repository is essentially correct - so the best general approach would be to do the same for the service. There's a lot of advantage in having a consistent architecture and approach.

The big caveat with that is managing the dependencies; my general assumption is scenarios like this is that the physical data access is abstracted out - so that the model isn't technically tied to SQL, the file system, etc. using this approach will allow you to expose different data from different repositories in a consistent manner.

  • Your idea of using lazy Load is good; and if you abstract out the technical dependencies your main concern with that option goes away.
  • A separate service class might seem like overkill but it's a small price to pay if it means it gives you better control over dependencies.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM