0

I am trying to understand a general pattern. Suppose I have an application where I show User and all the Jobs listings where he has applied, here User and Job are many2many relationship. In the same interface I need to show the all the Address of the logged in User.

So, I will have following classes:

class User {
  List<Address> address = null;
  List<Job> jobs = null;

  public List<Job> getJobs() {

  }

  public List<Address> getAddress() {

  }
}

Above I am assuming that to get both jobs and address I have to get hold of the user instance first which in itself requires a database call.

So, either I can fetch all the information at once through joins and then send them to the client or I can opt for lazy loading the data when required so, if there is a separate tab for jobs then I can request jobs but I need to create an instance of the user first and the call getJobs which would internally make DB call for fetching jobs, so overall there will be two database calls for fetching every related object which seems a overhead to me.

Well my real concern is that the data needs to come through database which know nothing about my objects and vice versa, how to resolve this dilemma?

  • What do you mean by "In the same interface I need to show all the Address of the logged in User"? Are you talking about a GUI? – Ben Cottrell Mar 19 '17 at 9:43
  • Yes, you are right – CodeYogi Mar 19 '17 at 9:45
  • 1
    In an interactive scenario, a database call does not seem like a big deal to me. Getting current data the moment you click seems more important. Assuming it is an administrstive app and not a public website catering to thousands of users at any moment. – Martin Maat Mar 19 '17 at 12:28
  • The structure of the objects should be driven by the constraints of the integrations, the interface, and the state you keep. Forget about patterns and about trying to make it "correct" and write the smallest amount of code that fits the need and is efficient, readable, maintainable and extensible. Let the system's requirements dictate the object structure. – dietbuddha Mar 19 '17 at 19:26
  • @dietbuddha so for my use cases how you would have started? – vivek Mar 20 '17 at 1:05
2
  • Start with the most simple implementation you can think of, without investing too much thought about "too many database calls". For example, implement something without lazy loading and three db calls (select from User, select from Jobs, select from Address).

  • Then, use this in your program and try out if it is fast enough for your purporses. If that is fine, don't waste your time by optimizing this any more.

  • However, if this solution turns out not to be fast enough, you can still add optimizations afterwards. These optimizations should fit to your use cases. For example, if the bottleneck is a use case where lots of users are fetched without the need for jobs and addresses, lazy loading jobs and addresses "on demand" might be a good solution.

  • If you have an additional use cases where you often need users together with their jobs and addresses, you can provide an additional, optimized loading implementation, getting these data by a complex join in one query. If that is the case, you need to design your fetching interface in a way the caller can control to load a user together with all addresses and jobs "preloaded", or not (so jobs and addresses will be loaded only "on demand").

The resulting code is not DRY any more, because now you have a equivalent loading logic implemented twice, using different means of queries. But that is unavoidable: optimization is often a trade-off between maintainability or speed, so do not optimize without any real need.

  • Ok let's forget about database for now, what should my object's behaviour? should I go through user to fetch address because conceptually an address belongs to user? Where can I get some relevant materials to get deeper into this topic? – CodeYogi Mar 19 '17 at 13:32
  • @CodeYogi: you are responding as if you had asked the question. Are you using two different accounts? But to answer your question: if you want addresses or jobs conceptionally belong to a user or not is your own design decision, the "correct" way depends on the domain and the use cases your model shall support. – Doc Brown Mar 19 '17 at 18:12
  • @DocBrown thinking more, is it possible given a set of features designing the object relationship without implementation details like database? – vivek Mar 20 '17 at 3:39
  • @vivek: isn't that obvious? The example in your question shows already an object relationship without any database details. However, the kind of persistence one has in mind has often some influence on the object design, of course. OR mapping tries to abstract from individual databases, however by using an ORM framework, one has to obey the modeling rules imposed by that framework. These kind of abstractions tend to be leaky. – Doc Brown Mar 20 '17 at 7:44
0

Consider writing separate Repository classes which are responsible for querying your database, but which also don't contain any domain data themselves. (They might contain DB connection state or something similar but no actual domain data)

When working with query results, the ideal solution is to map on to plain 'model' entities which only contain properties and no logic (i.e. don't treat mapped entities as objects, because their responsibility is only to bridge the gap to your database).

Consider changing the User into a UserModel which contains only data properties mapped from your database, and no logic. (also consider Job to JobModel for consistency)

Secondly, use several Repository classes for querying the database and returning that data mapped on to entity classes; i.e.

  • UserRepository to query and map UserModel data
  • JobRepository to query and map JobModel data
  • AddressRepository to query and map AddressModel data

Each of your UI Views could choose what data they needs from each repository (if any) based on a query decided by the view controller, without placing a dependency on a User object.

Lastly, if a View needs something more than a single database model (and especially if it needs extra data which isn't from the database), consider letting your View Controller build ViewModels based on the models from your Repositories. For example:

class UserViewModel {
    UserModel user;
    List<AddressModel> addresses;
    bool isReadOnly;
}

ViewModels are useful for ensuring each View has the right data (and only the data it needs) without leaking UI concerns into the rest of an application. Common UI patterns such as MVC/MVP use ViewModels to decouple any special UI-behaviour or UI structures away from the rest of the app


Updated:

(In response to the comment about business logic)

Neither UI classes nor Database/persistence classes should be dealing with business logic. Most non-trivial applications need more than just the ability to pull data straight from a repository; an extra 'layer' in-between of classes and functions which contain that logic is the typical solution.

The business logic, app logic and other in-between classes would be used directly by the UI Controller classes - i.e. (Rough schematic):

 View --> Controller --> Business logic classes --> Repositories / External APIs / etc.

Arrows indicating the direction of each dependency. A View Controller may depend upon classes containing Business logic but not the other way around; Business logic classes may depend upon Repositories but Repositories would still know nothing of the business logic.

  • 1
    So, if I need some business behaviour then where should it belong? Like fetching all active address of an user? – CodeYogi Mar 19 '17 at 12:32
  • @CodeYogi anything more complex needs to sit in-between the two; I've extended the answer a little. – Ben Cottrell Mar 19 '17 at 15:46
  • So , the new thing here is the view model. Where it resides ? Server ? Client? Is there some example? Sorry for being naive but that's vwhat I am right now :) – CodeYogi Mar 19 '17 at 16:01
  • @CodeYogi ViewModels are always client-side. As Model objects are in-code mirrors of entities from the Database schema, they only address concerns which are close to the database and persistence. A ViewModel is a way to create a data structure which 'belongs to' a View, and can contain any number of fields/properties or other data models which are needed by that view. – Ben Cottrell Mar 19 '17 at 16:54
  • So UserViewModel resides in JS if my client is for web? – CodeYogi Mar 19 '17 at 18:04
0

The key problem

You can't decouple List<Address> address and List<Job> jobs from class User

Make custom classes to enable decoupling

These DSL style classes can be independently instantiated because they have appropriate functionality so that the User class is no longer acting as these missing classes.

public class UserAddresses {
   protected int UserId { get; set; }
   public List<Address> Addresses { get; protected set; }

   public UserAddresses ( int UserId, List<Address> myAddresses = null ) { }
}

public class UserAppliedJobs {
   protected in UserID { get; set; }
   public List<Job> AppliedJobs { get; protected set; }

   public UserAppliedJobs ( int userId, List<Job> myJobHopes = null ) { }
}

These classes will have Add, Remove, Find methods. They probably should have iterators, IEnumerable, IEnumerator implementations. Then any other functions that make them UserAddresses/UserAppliedJobs vis-a-vis any other kinds in your business model.

I imagine overriding Equals for "instance equality" - based on userId; assuming ever only one collection per user.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.