2

I have a DTO returned by my DAL. For example

public class CustomerDTO
{
    public int CustId {get; set; }
    public int CustType {get; set; }
    .
    . 
    .
    public string GetCustomerTypes{
      get {  if (CustType== 1) 
               return "Special Customer";
             else if(CustType==
}

Now I have multiple properties in my class which are not linked with any table & are just codes representing some attributes like for CustId I can have (1='Special Customer', 2='Defaulter'or 3='New Customer'). Now I need to display their attributes on the DTO.

I can embed my business logic either into SQL statements or my DTO class as I have done above. However, for various columns I end up with a lot of conditional logic. Also, incase I make another DTO, this conditional logic is repeated again.

How can I encapsulate this logic in my class design & avoid repetition?

Zo Has
  • 12,599
  • 22
  • 87
  • 149

4 Answers4

2

If a certain piece of logic is repeated, you should put it in a separate method. The placement of the method depends on the structure of your system, but generally you have three main options:

  • Put the logic into a helper class
  • Put the logic into a base class
  • Put the logic into an extension method

The first option is the simplest, and requires minimal modifications: simply add a class with a static method, like this:

static class DtoHelper {
    public static string GetCustomerType(int type) {
        ... // Custom logic goes here
    }
}

The second method is the least flexible, because it requires your DTOs to inherit a common class:

class WithCustomerType {
    private int custType;
    public string CustomerType {
        get {
            ... // Custom logic goes here
        }
    }
}
public class CustomerDTO : WithCustomerType {
    ...
}

The third option is more flexible, because it uses an interface instead of a type:

interface IWithRawCustomerType {
    int RawCustomerType {get;}
}
static class DtoExtensions {
    public static string GetCustomerType(this IWithRawCustomerType dto) {
        int type = dto.RawCustomerType;
        ...
    }
}
class CustomerDTO : IWithRawCustomerType {
    ...
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    You know, I have **never** considered doing something like this in code because it feels like a database operation. Putting the listings in the database also helps with reporting and listing those lists in combo boxes. ***However,*** with you're third approach, I like that one, a lot. Fantastic answer! – Mike Perrenoud Feb 27 '13 at 11:43
1

You can make the class partial and write the extra logic in the partial class. If it's common to all DTOs you can put that extra logic in a base class and inherit it in all partial classes that you create for your DTOs.

As for the problem with "translating" the type to a string, simply define the Enum CustomerType and set the text you want in a custom attribute for each of the values. That way the common logic you will have will be to return the Attribute value for the Type property you have in each entity.

Something like this: Get enum from enum attribute

So, for your example i would define an enum:

public enum CustomerType
{
[Tag("SpecialCustomer")]
SpecialCustomer = 1,
...
}

then in the partial class (if the entitites are generated code) i would wrap the default member into a property like so:

public string CustomerTypeAsString
{
 get
    { 
        return GetTagValue(CustType);
    }
}
Community
  • 1
  • 1
dutzu
  • 3,883
  • 13
  • 19
1

I'm going to recommend you put these values in the database. You could build separate tables like:

CREATE TABLE CustomerTypes (
    ID INT PRIMARY KEY IDENTITY(1, 1),
    Name VARCHAR(50) NOT NULL
)

or you could build one table with a type code in it like:

CREATE TABLE ListTypes (
    ID INT PRIMARY KEY IDENTITY(1, 1),
    Name VARCHAR(50) NOT NULL,
    TypeCode CHAR(2) NOT NULL
)

either way, when you gather the DTO from the database, join to those tables and grab that value. So if you built one table it might look like:

SELECT c.*, ct.Name FROM Customer c
    JOIN CustomerTypes ct ON ct.ID = c.CustType

and if you were to use the more generic table with the type code it might look like this:

SELECT c.*, lt.Name FROM Customer c
    JOIN ListTypes lt ON lt.ID = c.CustType AND lt.TypeCode = '01'

The reason this approach will work so well for you is because you need the string value, but only for display purposes, and you're going to need it on a lot of types going forward. Further, you're already in the database getting the entity, so let the database do this work. Finally, if you ever wanted to list these values in a combo box and let the user select them, you could bind that combo box from the database rather than statically.

But in short, this makes your application much easier to modify and expand.

Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
  • Hi Michael, Thanks for your reply. That would help me in reporting as well ! I can do that however I have to request the DBA for that as it is an inhertited database. Can you advise on achieving this through class design? – Zo Has Feb 27 '13 at 11:39
  • 1
    @DamienJoe, are you saying you can't go through to DBA to do this, or are you saying you're looking for another option just in case they don't go for it? – Mike Perrenoud Feb 27 '13 at 11:41
  • Hi Michael, There are about 15 fields on my table which are like this. Most are set of 2 to 3 values. I am requesting another option just incase the DBA rejects the whole idea. – Zo Has Feb 27 '13 at 11:46
  • If you're looking for another option, go with the one provided by @dasblinkenlight - and use the third option if you can - it's a fantastic answer! – Mike Perrenoud Feb 27 '13 at 11:48
1

what about the extension methods

 public static  class DerivedValues
 {
     public static void ToCustomerTypes(this CustomerDTO dto)
     {
             if (dto.CustType == 1)
             dto.GetCustomerTypes = "Special Customer";
     }
 }

main use

var c1 = new CustomerDTO();
        c1.ToCustomerTypes();
TalentTuner
  • 17,262
  • 5
  • 38
  • 63