Living in the Tech Avalanche Generation

A practitioner’s introspective on technology
Archive for October 16th, 2008

IronRuby with LINQ To SQL (kinda)

I have been playing around with IronRuby a bit just of late and I was curious to see whether it was at a stage where it was working with LINQ To SQL. It was clear from the outset that using LINQ To SQL in the most common way (with full UI experience) in VS.Net was simply a silly thing to expect and it became immediately apparent that any benefit of IEnumerable<T> or IQueryable<T> was out the window also. Given that that any attempt to access IEnumerable<T> from any instance of Table<T> was for now a journey into folly, I tried briefly to circumvent that approach and see if I could POCO my way to an outcome with Mapping files. Listing 1.0 shows this unfortunately doomed venture.

Attempt No # 1.0

First the C# POCO Entity class required in the RubyCustomer library.

using System;

namespace Org.TechAvalanche.Orm.Tests.Domain
{
    public class Customer
    {
        private string _CustomerID;
        private string _CompanyName;
        private string _ContactName;
        private string _ContactTitle;
        private string _Address;
        private string _City;
        private string _Region;
        private string _PostalCode;
        private string _Country;
        private string _Phone;
        private string _Fax;

        public Customer() { }

        public string CustomerID
        {
            get {return this._CustomerID;}
            set {this._CustomerID = value;}
        }

        public string CompanyName
        {
            get {return this._CompanyName;}
            set {this._CompanyName = value;}
        }

        public string ContactName
        {
            get {return this._ContactName;}
            set {this._ContactName = value;}
        }

        public string ContactTitle
        {
            get {return this._ContactTitle;}
            set {this._ContactTitle = value;}
        }

        public string Address
        {
            get {return this._Address;}
            set {this._Address = value;}
        }

        public string City
        {
            get {return this._City;}
            set {this._City = value;}
        }

        public string Region
        {
            get {return this._Region;}
            set {this._Region = value;}
        }

        public string PostalCode
        {
            get {return this._PostalCode;}
            set {this._PostalCode = value;}
        }

        public string Country
        {
            get {return this._Country;}
            set {this._Country = value;}
        }

        public string Phone
        {
            get {return this._Phone;}
            set {this._Phone = value;}
        }

        public string Fax
        {
            get {return this._Fax;}
            set {this._Fax = value;}
        }
    }
}

coupled with the following LINQ To SQL Mapping file

<?xml version=”1.0″ encoding=”utf-8″?>
<Database Name=”Northwind”
    xmlns=”http://schemas.microsoft.com/linqtosql/mapping/2007″>
  <Table Name=”Customers” Member=”Customer”>
    <Type Name=”Org.TechAvalanche.Orm.Tests.Domain.Customer”>
      <Column Name=”CustomerID” Member=”CustomerID” DbType=”NChar(5) NOT NULL”
          IsPrimaryKey=”true” CanBeNull=”false” UpdateCheck=”Never” />
      <Column Name=”CompanyName” Member=”CompanyName”
          DbType=”NVarChar(40) NOT NULL” CanBeNull=”false” UpdateCheck=”Never” />
      <Column Name=”ContactName” Member=”ContactName”
          DbType=”NVarChar(30)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”ContactTitle” Member=”ContactTitle”
          DbType=”NVarChar(30)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”Address” Member=”Address”
          DbType=”NVarChar(60)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”City” Member=”City”
          DbType=”NVarChar(15)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”Region” Member=”Region”
          DbType=”NVarChar(15)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”PostalCode” Member=”PostalCode”
          DbType=”NVarChar(10)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”Country” Member=”Country”
          DbType=”NVarChar(15)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”Phone” Member=”Phone”
          DbType=”NVarChar(24)” CanBeNull=”true” UpdateCheck=”Never” />
      <Column Name=”Fax” Member=”Fax”
          DbType=”NVarChar(24)” CanBeNull=”true” UpdateCheck=”Never” />
    </Type>
  </Table>
</Database>

and now our IronRuby attempt to talk DIRECTLY LINQ To SQL.

require ‘mscorlib’
require ‘System.Core, Version=3.5.0.0,
  Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘System.Windows.Forms, Version=2.0.0.0,
  Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘System.Data.Linq, Version=3.5.0.0,
  Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘RubyCustomer, Version=0.0.0.0,
  Culture=neutral, PublicKeyToken=c1aba19d9dedea39′

begin

  #get the mapping into a stream
  stream = System::IO::StreamReader.new(“C:\\Users\\simon.segal” +
    “\\Desktop\\IronRuby\\ironruby\\bin\\DomainMapping.xml”)
  mapping_file =
    System::Data::Linq::Mapping::XmlMappingSource.
      FromStream(stream.BaseStream)
  #new up a DataContext with our mappings
  db = System::Data::Linq::DataContext.new(“server=localhost;initial “+
    “catalog=Northwind;user id=sa;password=supremo”, mapping_file)
  #new up a POCO customer from my C# library
  cust = Org::TechAvalanche::Orm::Tests::Domain::Customer.new
  #not sure if typeof works in IronRuby
  cust_type = cust.GetType()
  #load the table of customers from northwind
  custs = db.GetTable(cust_type)
  #tried to get enumerator but .Current gets a method error 
  #and so ends our journey
  list = custs.GetEnumerator()
  puts “The call to GetEnumerator returned a “ +
    list.GetType.ToString()
  currentCust = list.Current
  rescue Exception => ex
    puts “someone is missing a method!” + ex.to_s
    #just to prove that it’s a Table<Customer>
    puts “Just to show that we did get as far as “ +
           “getting the Table<Customer> : “ +
           custs.ToString()

end

Which yields the following output from standard IO (click to see full view):

ironLinqToSqlFailedOutput

So as you can see here, we get close but no cigar. Ready to give up - damn, not yet! Lets move all the LINQ To SQL code into our custom library and call it from IronRuby - that should work? We already had a POCO in our library referenced above (see the require ‘RubyCustomer’). So here we go.

Attempt No # 2.0

As a jumping off point for attempt # 2, I thought it might be time to check out Ruby In Steel, a third party integrated UI platform for VS.NET and IronRuby. I wanted to be able to keep my C# library with the LINQ To SQL code and the IronRuby consumer code in a single solution if possible and I was looking for a bit of holiday from writing Ruby Code in SciTE and NetBeans, therefore looking at Ruby In Steel had been on the agenda for a while so I figured now was as good a time as any. This gave me a more instantly gratifying experience in developing a Windows Form to present my LINQ To SQL data as well:

Ruby In Steel

As you can see I have my C# project and my IronRuby project coupled together in a single VS.Net solution and whilst Ruby in Steel is not quite as stable or fully featured as you would expect it to be when IronRuby makes it’s official debut, it certainly helped speed things up quite a bit.

The LINQ To SQL code consisted of a run of the mill repository, POCO and mapping file (the entity itself remained as is - see above Customer Class).

using System.Data.Linq;
using System.Linq;

namespace CsharpLinqToSqlForIronRuby
{
    public class CustomerRepository
    {
        private readonly DataContext _context = null;

        public CustomerRepository(DataContext ctx)
        {
            _context = ctx;
        }

        public Customer[] All()
        {
            Customer[] retCustomers = null;
            using (_context)
            {
                retCustomers = _context.GetTable<Customer>().ToArray();
            }
            return retCustomers;
        }

        public Customer FindById(string custId)
        {
            Customer retCustomer = null;

            using (_context)
            {
                retCustomer = _context.GetTable<Customer>().
                    Where(c => c.CustomerID == custId).Single();
            }
            return retCustomer;
        }
    }
}

On the IronRuby side of things, we dialled up a class to handle calling our C# Repository library:

require ‘mscorlib’
require ‘System.Core, Version=3.5.0.0, ‘ +
    ‘Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘System.Windows.Forms, Version=2.0.0.0, ‘ +
    ‘Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘System.Data.Linq, Version=3.5.0.0, ‘ +
    ‘Culture=neutral, PublicKeyToken=b77a5c561934e089′
require ‘D:/simon.segal/LocalWorking/IronRubyProofs/’ +
    ‘IronRubyWithLinqToSqlForms/IronRubyWithLinqToSqlForms/’ +
    ‘CsharpLinqToSqlForIronRuby.dll’

class CustomerController

    def GetAllCustomers

        #get a stream of the mapping file
        stream = System::IO::StreamReader.new(“D:\\simon.segal\\” +
            “LocalWorking\\IronRubyProofs\\” +
            “IronRubyWithLinqToSqlForms\\” +
            “IronRubyWithLinqToSqlForms\\DomainMapping.xml“)
        #set the mapping source
        mapping_file = System::Data::Linq::Mapping::XmlMappingSource.
            FromStream(stream.BaseStream)
        #new up a DataContext with our mapping
        db = System::Data::Linq::DataContext.new(”server=localhost;initial ” +
            “catalog=Northwind;user id=sa;password=supremo”, mapping_file)
        #new up our repository
        cust_repos = CsharpLinqToSqlForIronRuby::CustomerRepository.new(db)
        #get all the customers
        custs = cust_repos.All()
        #print customers to the console window (in debug)
        custs.each {|cust| puts cust.CompanyName}

        return custs

    end

end

And what we needed now was an IronRuby WinForm to do the presentation work and data binding for us:

ironrubyForm

with the following code behind:
require ‘Form1.designer.rb’
require ‘CustomerController.rb’

class Form1

    #form load
    def Form1_Load(sender, e)
    end

    #button click event handler
    def button1_Click(sender, e)

        controller = CustomerController.new
        self.comboBox1.DisplayMember = “CustomerID”
        self.comboBox1.ValueMember = “CustomerID”
        custs = controller.GetAllCustomers.each {|customer|
            self.comboBox1.Items.Add(customer)}
        self.lstCustomer.DataSource = custs
        self.lstCustomer.DisplayMember = “CustomerID”
        self.lstCustomer.ValueMember = “ContactName”

    end

    #combo box selected index changed handler
    def comboBox1_SelectedIndexChanged(sender, e)
        cust = self.comboBox1.SelectedItem
        self.textBox1.Text = cust.CompanyName
        self.textBox2.Text = cust.ContactName
    end

    #list customer selected index changed handler
    def lstCustomer_SelectedIndexChanged(sender, e)
        cust = self.lstCustomer.SelectedItem
        self.textBox1.Text = cust.CompanyName
        self.textBox2.Text = cust.ContactName
    end

end
So unfortunately right at this moment there is no IronRuby to be had with LINQ To SQL unless it’s via one of the other .NET languages that support it. I would have been more than happy if I had been able to leverage my own custom Repository Framework to do the data access but that isn’t possible with the current limitations either.

Share/Save/Bookmark

No comments

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia