Question

This may be a bit of an odd question, and what I have in place now works, but it feels a bit strange to me and I wonder it's because of poor design/architecture. Any thoughts here would be appreciated.

The initial design is in a code base I inherited from someone else. We have a linq-to-sql class (auto generated in the dbml's designer file).


[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ARCustomers")]
public partial class ARCustomer : INotifyPropertyChanging, INotifyPropertyChanged
{
    // variables
    // extensibility method defs
    // ctor
    // properties
    // etc.
}

Then another class class called ArCustomer (notice the lower case "r") that is an extended version of the auto-generated class. When I say extended, I mean it has all the properies of the LINQ class, plus a few more that requires some logic to populate.

There are a lot of places in code that we want to take an ARCustomer and turn it into an ArCustomer. So I wrote an extension method (this is what felt strange) on the ArCustomer class.


public static ArCustomer FromDatacontextObject(this ArCustomer customer, ARCustomer datacontextObject)
{
    var arCustomer = new ArCustomer();
    arCustomer.Id = datacontextObject.ProjectID;
    // more of the same

    // now populate the other fields that don't exist on the datacontextObject

    return arCustomer;
}

It's called as such.


var customerfromDb = accountReceivableRepository.GetCurCustomer(arId);
ArCustomer customer = new ArCustomer();
customer = customer.FromDatacontextObject(customerfromDb);

This feels wrong to me, but I don't know of any better alternatives off the top of my head. (Would a partial class that contains the extended properties work? Populate them in it's constructor?) Or maybe it's fine... I'm interested in a few things...

  1. Am I right in feeling that this is wrong/odd/bad?
  2. Specifically, what are the cons to be found in the solution I've implemented? I feel like one is that I scratch my head too often trying to differentiate between the two classes and figure out which is which.
  3. Are their any pros?
  4. Any better solutions (and why they're better)?

(Unrelated - I hope this kind of question is OK for stack overflow. I almost feel like I'm asking for a mini code review, which can be subjective; on the other hand, I tried to ask some concrete questions and feel I must not be the only developer to have ran into a situation like this ("I have one object and need to turn it into another"), so hopefully there is something to be gained from leaving the thread open).

Thanks guys!

Was it helpful?

Solution

Your instincts serve you well.

Having two classes with the same name (differing only be case) is technically allowed by the C# compiler, but it is a bad idea. Also, it is not CLS compliant.

It is a bad idea for the exact reason that you already stated: readability. Don't underestimate the importance of readability. Personally it is my number one measure of code quality. Readable code tends to have fewer bugs, and is easier to debug/maintain.

The classes generated by LINQ to SQL are already partial classes. You can add a separate code file to define any extra parts that you want. And, this is the preferred method to accomplish what you are describing. It is easier to maintain and understand.

Alternatively, you could create a "ViewModel" class that contains the ARCustomer. (This depends on your architecture).

OTHER TIPS

If you change the extension method to extend the database object you have a more natural API IMO

public static ArCustomer ToDomainObject(this ARCustomer datacontextObject)
{
   var arCustomer = new ArCustomer();
   arCustomer.Id = datacontextObject.ProjectID;
   // more of the same

   // now populate the other fields that don't exist on the datacontextObject

   return arCustomer;
}

then the data access code looks like this

var customerfromDb = accountReceivableRepository.GetCurCustomer(arId);
ArCustomer customer = customerfromDb.ToDomainObject();

Few days ago I had the same problem. And I did find some discussions on this topic. These threads might help: Thread one, Thread two

As I figured out, there is no better way to do what you are doing. However, you might try to use reflection to iterate through all the fields in parent object to copy them to relevant fields in child object. Some example code here, And discussion here.

For my problem, ended up going field by field manually, as some of the fields I needed to be deeply cloned, some had to be copied only by reference.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top