From DataSets to LINQ


After my last post I started working through a Repository pattern using DataSets. As I was playing with the idea, I got a call confirming that I was going to have to open up the data to a Java solution created by a vendor. Looking at the returned XML, I opted to punt on the DataSet. I am a bit leery when throwing complex objects like a DataSet at developers I cannot personally vouch for the skill of.
 
So, I looked at two options.
 
The first was to roll my own objects. This worked fine and created rather simple object definitions in the WSDL. This is a nice fallback if I find I have oops things again. Here is the class, as it started. I added some methods later, but this will give you an idea.
 
And here is the WSDL when returned from a web service:
 
<s:complexType name="Sim">
  <
s:sequence>
    <
s:element minOccurs="1" maxOccurs="1" name="SimId" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="SimStatusTypeId" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="SimUploadId" nillable="true" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="MobileCountryId" nillable="true" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="MobileNetworkId" nillable="true" type="s:int" />
    <
s:element minOccurs="0" maxOccurs="1" name="SimNumber" type="s:string" />
    <
s:element minOccurs="0" maxOccurs="1" name="IMSI" type="s:string" />
    <
s:element minOccurs="0" maxOccurs="1" name="MSISDN" type="s:string" />
    <
s:element minOccurs="1" maxOccurs="1" name="CreatedOn" type="s:dateTime" />
    <
s:element minOccurs="1" maxOccurs="1" name="CreatedByUserId" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="ModifiedOn" nillable="true" type="s:dateTime" />
    <
s:element minOccurs="1" maxOccurs="1" name="ModifiedByUserId" nillable="true" type="s:int" />
  </
s:sequence>
</
s:complexType>
 
The second was to try LINQ to SQL. I have played with LINQ rather extensively, but have not had the opportunity to use it in a real world application. So, I had to ask the question "Can I use LINQ objects via a web service without making the resulting objects overly complex?". The answer, thus far, appears to be yes. In case you are from Missouri on this one, here is the WSDL for the LINQ created object.
 

<s:complexType name="Sim">
  <
s:sequence>
    <
s:element minOccurs="1" maxOccurs="1" name="SimId" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="SimStatusTypeId" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="SimUploadId" nillable="true" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="MobileCountryId" nillable="true" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="MobileNetworkId" nillable="true" type="s:int" />
    <
s:element minOccurs="0" maxOccurs="1" name="SimNumber" type="s:string" />
    <
s:element minOccurs="0" maxOccurs="1" name="IMSI" type="s:string" />
    <
s:element minOccurs="0" maxOccurs="1" name="MSISDN" type="s:string" />
    <
s:element minOccurs="1" maxOccurs="1" name="CreatedOn" type="s:dateTime" />
    <
s:element minOccurs="1" maxOccurs="1" name="CreatedByUserId" type="s:int" />
    <
s:element minOccurs="1" maxOccurs="1" name="ModifiedOn" nillable="true" type="s:dateTime" />
    <
s:element minOccurs="1" maxOccurs="1" name="ModifiedByUserId" nillable="true" type="s:int" />
    <
s:element minOccurs="0" maxOccurs="1" name="SimUpload" type="tns:SimUpload" />
    <
s:element minOccurs="0" maxOccurs="1" name="SimStatusType" type="tns:SimStatusType" />
  </
s:sequence>
</
s:complexType>

 
If you would like, you can compare the WSDL. The main difference is the addition of the elements that link (or is that LINQ – LOL) to the Sim object. And this is only because the three objects sit in a single DBML. If I were to add the other tables, we would find additional tns properties for those tables. Here is the part oft he WSDL that is different.
 
    <s:element minOccurs="0" maxOccurs="1" name="SimUpload" type="tns:SimUpload" />
    <
s:element minOccurs="0" maxOccurs="1" name="SimStatusType" type="tns:SimStatusType" />
 
I am going to assume this can be coded around. But, if not, I will create individual dbml files to make it so this does not create a problem in Java. THe first object should not. In fact, since my data context is disconnected, I may just bite the bullet and put each table in a separate DBML right now. Then my objects will identical and the vendor cannot complain that they cannot create a tns:XXX object. Just made a decision while blogging.
 

Web Service

If you have been following this series, you know I need to have things work with both a web serivce and a direct save to a database. I am going to accomplish this by creating a configurable factory to return the object that handles the client side "save". This method will not actually do the saving work, so it is safe. Underneath the hood, it will either call the web service or the database to save.

The only issue here is the web service yields objects in the CompanyName.ProjectName.ServiceName.ObjectName format, while the Data route yields objects in the form of CompanyName.ProjectName.ObjectName format. While the objects are funcationally equivalent, they are not exactly the same. Intially, I will pull properties over to a web service version, on a class by class basis. Eventually, I will take the time to see if can add attributes and genericize this translation, as both objects will contain the same properties.

Either way, this is a small price to pay for flexibility. Now I just have to figure the generic names for all of these pieces and where I am going to stick the factory. I am aiming for the business facade layer, as I can then easily switch the functionality from windows to web. I have not drawn it out, but it is midnight now, so I am going to call it quits for tonight.

Repository Pattern

I opted first for the first Repository Pattern in LINQ to SQL I could find. It is found here, on CodeProject. After a short bit of playing around, I quickly discovered why this will not work. Very nice use of interfaces, but you have to keep the DataContext open. I dinked a bit to get it dicsonnected, but then ran into a problem with the way objects are created. Not very useful for a completely disconnected system, like an app calling a web service for its data.

I am now looking at Andrew Siemer’s implementation of the Repository Pattern with LINQ to SQL. It is disconnected, but I have not completely refactored yet, so I am sure I will find a bump or two. But, it does seem to allow Disposing of the context between calls, which is absolutely mandatory for my work.

Final Thoughts

The application I am working on is not an Enterprise level application. It is a simple programming application, used to programming GPS units. It does contact a web service, but there will be, at max, two clients … at least for the foreseeable future. Because of this low scalability need, I am not going to look into LINQ and threading just yet, but I imagine this system will, at some time, require a more scalable solution. In short, the architecture will work for what I am doing, but I am not sure I am willing to sell anyone the idea until I see how LINQ works under heavy load.

I am also breaking one of my rules: LINQ is for IEnumerable and not for data access. My main reason for this is LINQ allows me to write far less code and completely genericize my data access. The reason I created "the rule" was I have found most of the problems with LINQ coming from people using LINQ as a DAL and not to iterate objects (filtering, etc.), which is its good point. I think I will be able to get away with it here, as I have buried the LINQ deeply enough it should not cause problems on other layers. I will use it again on the client layer, if I need selective filtering of lists. I do not have an example right now of when I would do this, but I am sure I will find an example at some time. Then you can see LINQ shine as something other than a data access technology (which it is not).

I had the same option with ADO.NET Entities, by the way. The problem there is described here. For those not interested in reading the other post, my biggest issue with the new Entity Framework was the fact that the value, when you have a foreign key, is extremely generic (allow you to have multi-field keys); while this is very cool, I knew it would not translate easily to Java. Add on that the complex WSDL and we have a no go. It also requires working with all of hte objects I am going to populate as well as anything they are linked to. And, the complexity of the code for maintenance kicked it over the top. Love the work, but it is not good for me right now.

Peace and Grace,
Greg

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: