Hanalei, Hawaii 9/2/2010
438 Posts and Counting

SubSonic 3.0 Preview 1: Linq Has Landed

Friday, November 07, 2008 -

I've been working a lot over the last few months on our next rev of SubSonic, and I think I have something that's good enough to issue as a preview. Please understand that this is a preview in every sense of the word, and may shatter into a zillion pieces and make you want to pour your Red Bull over my head. This is bleeding edge edge crazy talk. It's everything bad that wakes you up screaming at night, and quite possibly is the coolest thing I've ever made... or somewhere in between. Just know that if you download and play with it, you're in for a ride... maybe. Or maybe it will shine like a million suns at the dawn of man...

SubSonic 3.0 Is...
A complete rewrite. The culmination of the things I've learned over the last year as I've (once again) subferrariChanged Everything and shared some wonderful Koolaid with my Alt.NET buddies :). Seriously - I've ripped everything out and redone it, with a focus on:

  • Simpler
  • Lighter
  • Simpler
  • Meaner
  • Simpler
  • Better
  • Faster
  • Simpler

(Not in that order - but generally I've placed an emphasis on simplicity). I've installed interfaces everywhere, and focused on making everything lightweight, testable, and injectable. I hope. We'll see.

Overall I've had exactly 5 false starts. I literally have 6 folders on my hard drive right now, each named "SubSonic 3.0 [X]" where "X" is the iteration number. Sometimes it's a swear word - but I won't go there now. Linq is hard - no really - just ask Ayende. It's not a matter of smarts - it's just really hard to try to fit Linq in... trust me. I was hoping originally that I could just create an Expression parser and build stuff using our core bits... but umm... that didn't happen.

One of the blogger people I've been following as I've been working through all of this is Matt Warren, the Zeus of Linq To Sql. He has a great series of posts on how to implement IQueryable, and when he got to post number 9 I began to think I should just use his code wholesale (yes, I know it's cheap of me). He's now on post number 11, and I asked him a while back if I could just steal all of his code - and this is why Matt Warren is my personal Santa Claus - he said "yes - it's all under MS-PL anyway. Just forward the license". 

So there it is - the SubSonic.Linq namespace is 99.999999% Matt Warren's code. I've tweaked it a touch to work with our core Query stuff, but everything else is him and his large brain. Thank him for this and have a read on what you get with this provider.

My philosophy while developing SubSonic 3.0 is this:

  1. I really dig Linq as a language feature - I want to include it as a query tool
  2. I don't like all the extra "shmekt" that we have right now for things like Code Generation and figuring out how to rename bad table names
  3. I want to change our Provider Model - this can be much simpler
  4. I want to give you a lot more power to make code you want to use
  5. I want to use POCOs
  6. I want Linq to work where it should, SubSonic to work where it should, and seemlessly make them work together
  7. If I do this right, you can build on top of SubSonic, to do what YOU want to do.

There it is. And I want it to be stupid simple.

SubSonic 3.0 Is Not...
I think this is as important as what I want to do. So, what I don't want to do is:

  • Take over as the new Linq To Sql. I know this is weird timing, given the latest grumblings happening in .NET space, but believe me Linq is scarey, and translating Expressions to SQL is not easy. It's really, really hard (see below) and if I didn't like Linq so much (and IQueryable) I would have kicked it to the curb.
  • Create another ORM. SubSonic's not an ORM believe it or not. There is no "mapping" ability really - I spose you can say it's "ORM-y". It's a data access tool for sure - I'll leave the mapping to you, which is why I decided to use Linq cause it makes is very simple.
  • Suggest in any way that we're done. There's some work to do here :) so this is for you to play with sort of like a sleeping cat (which could scratch you) or a pocket full of kryptonite. It's preview and may splode.
  • Backwards Compatible. Yes I know this will bum a lot of people out but it's the only way I can really rev this thing properly. Eric and I stressed over this, but the issue is that language/tooling features are letting us do something completely different and if it helps trim the API, bloat, and footprint than that's what we do. Very sorry about this.

Onward! To Some Code!

The Setup
To use SubSonic 3.0 you'll need to do exactly 3 things (assuming you're using .NET 3.5, which is required):

  • Create project references to SubSonic, System.Data, and System.Core (if you don't have it already)
  • Make sure you have a connection string (at least one), with the providerName set appropriately (usually it's System.Data.SqlClient)
  • Drop in the T4 templates, edit the connection string in "Connection.tt", and watch it generate your action.

No providers, no funkiness. That's it!

Generated Code
There are fiveT4 templates as of right now (this will probably change), and they are:

  1. Connection.tt - this is a non-code template (utility) that gets included with the other templates and does things like connect to your DB to get a list of tables and SPs, etc.
  2. Classes.tt - this T4 template generates 1 class per table in your DB using POCOs
  3. Provider.tt - this class wraps your Database in a class and adds IQueryable<T> fields as well as some factory methods for SubSonic queries (more below).
  4. SPs.tt - wraps your Stored Procedures and "appends" them to your provider class so you can call them as methods
  5. Structs.tt - wraps the columns and tables in your database so you can refer to them without using strings.

There's a lot more you can do here - and that leads me to the next thought...

This Aint No ORM Disco
The "Big Guy" ORMs (NHibernate, EF, Linq To Sql) keep track of an object's state and interacts with the DB in what's known as a "Unit of Work". This can be great sometimes, a PITA others. I've realized that ORMs are a slippery slope in this regard, and no one can really agree on what they should really do, when, and why.

So I've decided to focus one step below and try to make data access and manipulation silly simple. That way, in the future, maybe I (or you!) can work up some cool ORM templates to sit on top of the core SubSonic bits, and we can all share and have a party.

Just know that my focus, for right now, is to make working with the DB bloody crazy simple. The more complicated stuff can come later (eager loading, unit of work, etc) in the form of T4 templates.

Enough Already - Show Me Some Code!
The meat of the system is worked up by Provider.tt. This is a "wrapper" for your database and allows you to work with IQueryable and SubSonic at the same time:

namespace Northwind{
    public partial class DB{
    
        public IDataProvider DataProvider = new DbDataProvider("Northwind");
        public  DbQueryProvider provider;

        public Query<CustomerDemographics> CustomerDemographics;
        public Query<Region> Region;
        public Query<Employees> Employees;
        public Query<Categories> Categories;
        public Query<Customers> Customers;
        public Query<Shippers> Shippers;
        public Query<Suppliers> Suppliers;
        public Query<EmployeeTerritories> EmployeeTerritories;
        public Query<Order_Details> Order_Details;
        public Query<CustomerCustomerDemo> CustomerCustomerDemo;
        public Query<Territories> Territories;
        public Query<Orders> Orders;
        public Query<Products> Products;        
        
        public Select Select() {
            return new Select(DataProvider);
        }
        public Insert Insert() {
            return new Insert(DataProvider);
        }        
        public Update<T> Update<T>() where T:new(){
            return new Update<T>(DataProvider);
        }
        public Delete Delete(){
            return new Delete(DataProvider);
        }

There's more that's generated here - but I'll get to that in a second. To use IQueryable, you do what you normally do with Linq To Sql:

    Northwind.DB db = new Northwind.DB();
    var products = from p in db.Products
                   where p.CategoryID == 5
                   select p;
    foreach (var p in products) {
        Console.WriteLine(p.ProductName);
    }

Which produces what you might think (using delayed execution):

results1

Nothing really extraordinary about this - we've seen it before :). Most things are covered using the Linq provider that Matt started, but I'm sure there are some things missing - the good news there is that you have SubSonic's query tool to back you up if you get stuck (which is a lot of fun since you're not locked into one way of doing things now):

    var products2 = db.Select.From<Northwind.Products>()
        .Where(Northwind.ProductsTable.CategoryID)
        .IsEqualTo(5)
        .ExecuteTypedList<Northwind.Products>();

Note that you can also just use a string in the Where() statement.

And if you really get stuck, we've got your back so you can avoid all of the "Proprietary Object Noise" (with apologies to Jeff Atwood):

    var products3 = new CodingHorror("SELECT * FROM Products WHERE CategoryID=@id", 5)
        .ExecuteTypedList<Northwind.Products>();
    foreach (var p in products2) {
        Console.WriteLine(p.ProductName);
    }

I Like Lambdas
I've tried to rethink everything in terms of how the bits are put together so we can flex the changes in the language. To that end I've included lambdas where appropriate to add some type-safety etc. I know some people don't like em, but they're optional, as always.

    db.Insert.Into<Northwind.Region>(x => x.RegionID, x => x.RegionDescription)
        .Values(6, "Hawaii").Execute();
    object avg = db.Avg<Northwind.Products>(x => x.ProductID);

The latter example here is why I love lambdas so much - they can (if implemented properly) "terse up" your code nicely. You could use Linq on db.Products for this as well - but I like the terseness of this one line :).

All of our aggregates are now reachable from the db wrapper class:

    db.Avg<Northwind.Products>(x => x.ProductID);
    db.Sum<Northwind.Products>(x => x.ProductID);
    db.Count<Northwind.Products>(x => x.ProductID);
    db.Min<Northwind.Products>(x => x.ProductID);
    db.Max<Northwind.Products>(x => x.ProductID);
    db.Variance<Northwind.Products>(x => x.ProductID);
    db.StandardDeviation<Northwind.Products>(x => x.ProductID);

The best part is that if you don't like any of this, just change your template! It's all right there for you to tweak and alter to fit your project, which is a major goal of mine here: I want to give you the power to use SubSonic as you please. And if you do it better than us (which I'm sure you will) - perhaps you'll share. My focus is on the engine - you guys can hop it up with chrome and neon.

The biggest support issue we've had is with regards to our generated stuff. Specifically how we name objects. Our code generation is now completely transparent so if you don't like it - you can change the name of that table to be what you like!

Using System.Data.Common
At the core of the flexibility we now have is our use of System.Data.Common and the DataFactory pattern. If you don't know what this is, have a read here. The idea behind System.Data.Common is that we shouldn't have to rewrite all of our data access stuff if we happen to change database platforms. To that end the DataFactory pattern was created so that ADO data provider developers could write against a common API, and you could benefit.

We've used that to our advantage with SubSonic 3.0. So if you need to switch your DB provider, for instance, you can change from this:

    <connectionStrings>
        <add name="Northwind" 
connectionString="server=.\SQLExpress;Integrated Security=true;database=northwind;" providerName="System.Data.SqlClient"/> </connectionStrings>

To this (provided you have the DLL in your /bin):

    <connectionStrings>
        <add name="Northwind" 
connectionString="server=localhost;user id=root;pwd=HAHA?;database=northwind;" providerName="MySql.Data.MySqlClient"/> </connectionStrings>

There is no other setting - no "provider tweaks", no jiggity dances and prayers. The only assumption here is that you have the same DB on your target platform (which I do - I've ported Northwind to MySQL) and run:

results2

Most database providers support ADO.NET 2.0 and the Data Factory. Some off the top of my head that I know of are MySQL, Oracle, and SqlLite and I'm sure there are others - I just don't know.

You can download SubSonic 3.0, Preview 1 here.

We're still actively working on it and I'm sure you'll encounter bugs, etc. Feel free to send me an email (see the README) and please try to let me know what you were doing in the context of Northwind, so I can repro the issue.

As always, please be patient.

Epilogue: SubSonic.Sugar is now SubSonic.Extensions.
Wanna have some fun? Have a look at the SubSonic.Extension methods that I've ported from the Sugar class and turned into applicable extensions. To use them, you'll need to make sure you reference the appropriate namespace:

    using SubSonic.Extensions.Strings;
    using SubSonic.Extensions.Dates;
    using SubSonic.Extensions.Files;
    using SubSonic.Extensions.Linq;
    using SubSonic.Extensions.Numbers;
    using SubSonic.Extensions.Objects
    using SubSonic.Extensions.Validation;

In there is some fun, and some damn handy utilities. Things like Date math, file creation and text loading, string pluralization, regex validation and matching (Validation's "Is" functions rock - things like "IsValidEmail" and "IsCreditCard" are super groovy).

I mention them last as they are, literally, sugar utilities to help you through your day, and help us with SubSonic. They're not the main point at all.

Related


Gravatar
robconery - Wednesday, April 08, 2009 - Can you log this in our issue tracker with some more code? First question,

though, is why in the world are you specifying 2 unique columns and running

a FK on the non-PK string? 99% of my brain can't see why you'd do that - but

1% of it is intensely interested :)
Gravatar
Stefano - Tuesday, April 07, 2009 - Hello,

I think there is a problem with Foreign Keys. I have the main table with an integer identity primary key and a unique constraint on a string column (I know, it's a bad design ...).

If another table has a foreign key pointing to the unique string column, SubSonic generates wrong code:



public IQueryable MainTables {

get{

XXX.DB _db =DB.CreateDB();

return from items in _db.MainTable

where items.ID_COLUMN == _CODE_COLUMN

select items;

}

}
Gravatar
Dan - Friday, April 03, 2009 - You should some indication that there is a subsonic 3 coming on http://subsonicproject.com/, it might alleviate some of the queries about subsonic being dead. Took me quite awhile to find this and from looking at subsonicproject.com it appears the project when quite at around June 2008.
Gravatar
robconery - Saturday, November 08, 2008 - You need to ...



"Drop in the T4 templates, edit the connection string in "Connection.tt", and watch it generate your action."

there is more detail in the README.txt as well. You just need to drop the TT files into your project - they're magic.
Gravatar
johnsheehan - Saturday, November 08, 2008 - Here's a patch to ensure the generated Provider.cs file has the tables in the same order every time (makes it easier to use with vcs):



DataTable SortDataTable(DataTable tbl, string sort) {

tbl.DefaultView.Sort = sort;

return tbl.DefaultView.ToTable();

}



DataTable GetTables(){

string[] excludeTables= new string[]{"sysdiagrams","SubSonicSchemaInfo"};

DataTable tables = GetConnection().GetSchema("Tables");

return SortDataTable(tables, "TABLE_NAME");

}





Gravatar
Calixto - Monday, November 10, 2008 - Wow.... I found the problem....

Try file/new web site (Shift + Alt + N).... in this case t4 templates doesnt work.

When I tried file/ new project/ web application all the stuff works fine! :)

I need to learn about the differences about "web site" and "web applications".... I always use the first one to create my projects.

Thanks Rob!
Gravatar
cowgaR - Saturday, November 08, 2008 - peace bro, it was a joke... but maybe my english hasn't matured for it
Gravatar
robconery - Saturday, November 08, 2008 - ROFL - that was a good one :):)
Gravatar
Ibleif - Saturday, November 08, 2008 - In the best Rob style... a screencast would really rock.
Gravatar
M A - Saturday, November 08, 2008 - I am new to Subsonic, this is what I have done so far, PLEASE help me, I have:



Added a reference to SubSonic.dll.

Added a reference to System.Data and System.Core.

Drop the 5 T4 templates (*.TT) into my App_Code folder.

Changed the connection string and ProviderName in Connection.tt to point to the Northwind DB.



So what's next? I did build the project but nothing happened, I don't see any generated code, I cant even do the below:



Northwind.DB db = new Northwind.DB();



??? I am missing something?
Gravatar
robconery - Saturday, November 08, 2008 - Each TT file will create a ".cs" file - this is C# only for now. So-



1) Are there any CS files generated? They'll be right under the TT file

2) If not - try putting them in the root of the project, or anywhere other than App_Code

3) Is Northwind installed in your DB cause you'll need that.
Gravatar
Charles Nurse - Saturday, November 08, 2008 - hey rob - looks cool
Gravatar
tommyk - Monday, November 10, 2008 - What is going on with the migrations? Are you going to go forward with that?
Gravatar
robconery - Tuesday, November 11, 2008 - How would your application use the database?
Gravatar
Yogesh - Saturday, November 08, 2008 - You must be using AttachDbFilename in the connection string? If yes, use Database attribute and set the name of Database exactly the same as the name of the Provider in Connection.tt. Will solve your problem.
Gravatar
Yogesh - Saturday, November 08, 2008 - Rob...



I think you should mention it in the post that anybody using AttachDbFilename in the connection string will have empty classes if he is not using the Database attribute in the connection string. Database attribute needs to be set exactly the same as the name of the Provider in Connection.tt to solve empty class generation issue.
Gravatar
firefly - Saturday, November 08, 2008 - I am on the camp for new functionality and a lean and mean code base. Backward Compat is important and some migration guidance would be nice. But as we all know it's impossible so I am glad Rob went ahead with the decision of not worrying about Backward compatibility...
Gravatar
Yogesh - Saturday, November 08, 2008 - Or even better, change the GetPK, GetColumns and GetSPs in connection.tt class to this:



string GetPK(string table){

DbConnection connection = GetConnection();

string[] restrictions = new string[4] { connection.Database, null, table, null };

DataTable tbl= connection.GetSchema("IndexColumns",restrictions);

string pk="";

foreach(DataRow dr in tbl.Rows){

string index=dr["constraint_name"].ToString();

if(index.StartsWith("PK_")){

pk=dr["COLUMN_NAME"].ToString();

break;

}

}

return pk;

}



DataTable GetColumns(string table){

DbConnection connection = GetConnection();

string[] restrictions = new string[4] { connection.Database, null, table, null };

return connection.GetSchema("Columns",restrictions);

}



DataTable GetSPParams(string spName){

DbConnection connection = GetConnection();

string[] restrictions = new string[4] { connection.Database, null, spName, null };

return connection.GetSchema("ProcedureParameters", restrictions);

}

Gravatar
robconery - Monday, November 10, 2008 - Did you try to right-click and "Run Custom Tool"?
Gravatar
Martin Nyborg - Sunday, November 09, 2008 - No properties is equal to

- No Change events

- No databinding

- no broken rules collection

- no, no this is not good
Gravatar
Adam - Sunday, November 09, 2008 - Looks great so far, two things I noticed when getting a test project setup:



1) I had to right click each t4 template and choose 'Run custom tool' to generate the C# code

2) The columns from my test database were generated as fields rather than properties so DataBind didn't work with a GridView







Gravatar
robconery - Sunday, November 09, 2008 - We've got a fix coming soon. There are a few pending things that Eric is

looking at but we'll wrap up 2.1.1 very soon.
Gravatar
robconery - Sunday, November 09, 2008 - Agree with you RE needing properties - I'm workin on it :). Could use some

help if you're game :)
Gravatar
robconery - Sunday, November 09, 2008 - Yah that's a limitation for now - the LINQ stuff won't work with properties

if you can imagine that.
Gravatar
Jason Kealey - Tuesday, November 11, 2008 - No providers, no funkiness. That's it!



What if we have multiple databases that share the same schema or portion thereof. How are we going to support this scenario with SubSonic 3.0?
Gravatar
EtienneT - Monday, November 10, 2008 - I guess my main fear is that if we can't port to 3.0 (and a lot of people who are already using subsonic won't be able to), then we'll be stuck on 2.1 and I guess subsonic will lose a big chunk of it's fan base.



For people with a large code base of subsonic generated code (queries both in old and new query tool), can we expect to be able to port it to 3.0 with a lot of refactoring and modifying the templates or it'll just be impossible?
Gravatar
Kevin Pang - Friday, November 07, 2008 - Looks great Rob. Can't wait to play around with this. :-)
Gravatar
Elmar - Tuesday, November 11, 2008 - Rob, this is so cool. You are a Rockstar(2) ;-)).
Gravatar
Calixto - Monday, November 10, 2008 - This option (Run Custom Tool) doesnt exists in the right-click menu in my WebProjects.

In Console or ClassLibs projects the t4 templates works fine even Subsonic's template or any other that I created.

Gravatar
jkresner - Tuesday, November 11, 2008 - Congratulations :)!!
Gravatar
Brendan Kowitz - Tuesday, November 11, 2008 - very impressive, go Rob
Gravatar
wayde - Wednesday, November 12, 2008 - ah ok ... just wanted to make sure it wasn't going away.
Gravatar
juergen - Monday, November 10, 2008 - "To use SubSonic 3.0 you'll need to do exactly 3 things (assuming you're using .NET 3.5, which is required):"



Does that mean I need VS2008 in order to develop with Subsonic or do I only have to have the framework installed?
Gravatar
robconery - Tuesday, November 11, 2008 - I can't quite tell from your description here what the problem might be...

ummm...
Gravatar
jgeurts - Tuesday, November 11, 2008 - I wrote a post on how to add a Generate Code context menu item for website projects... checkout: http://biasecurities.com/blog/2008/visual-studio-website-project-add-context-menu-for-t4-files/
Gravatar
jf26028 - Saturday, November 08, 2008 - Yogesh!



Thanks for the heads up. I missed that detail in Rob's example.



Jesse
Gravatar
robconery - Monday, November 10, 2008 - You can use SubSonic with POCO's if you like, so no you don't need VS.
Gravatar
EtienneT - Friday, November 07, 2008 - Wohoo, looks great! I don't know how you find the time to do all this :).



Do you think it'll be possible to modify the templates to be backward compatible with existing code if we want to? Could you elaborate a little bit more on the backward compatibility point in a future post please?



Thanks Rob, great work as always!
Gravatar
Esico - Tuesday, November 11, 2008 - Great news. Especially the fact that you can still use the query tool which rocks.



Also very nice to hear about the 2.1.1 update !
Gravatar
robconery - Friday, November 07, 2008 - Sure - I can elaborate now. Backward Compat==0. I really am stuck on this one but the issue is that I need to advance and trim the core and shed some extra stuff. It comes at a price unfortunately :(.
Gravatar
mycall - Tuesday, November 11, 2008 - Can backwards compatibility come on the form of side-by-side assemblies within the same directory? :)
Gravatar
Yogesh - Friday, November 07, 2008 - I recently dumped EF when I heard about L2S and came back to what I loved best, SubSonic. Although I was a little worried after seeing this thread: http://forums.subsonicproject.com/forums/p/3883/15821.aspx#15821, I still was using SubSonic because it is a complete product for me (with a few workarounds ofcourse).



And man... did I made the right decision. Thanks a lot for this wonderful product Rob. Its a life saver. And believe me, even if I have to rewrite all my BLL, I will shift to this new version.



Thanks again.

Yogesh.
Gravatar
Yogesh - Friday, November 07, 2008 - BTW, one small suggestion. Make the namespace for the Sugar classes Subsonic.Extensions for all the static classes contained in the namespace without adding a seperate namespace node for them like Subsonic.Extensions.Dates. This way we only need to use only one namespace and all the functionality will be there. I also know that you might have a good reason not to do so. If there is, please tell me the secret too. :P
Gravatar
spootwo - Tuesday, November 11, 2008 - Looks freaking awesome! Thanks.
Gravatar
robconery - Friday, November 07, 2008 - The secret is Extension Method spam :). I want to make it "opt-in" for the goodies - too many extensions can make life difficult.
Gravatar
robconery - Sunday, November 09, 2008 - Fixed the Property issue :). Also set to partial. Will reload the bits tomorrow.
Gravatar
Jesse - Monday, November 10, 2008 - Very impressed with what I see. You've done it again;Not only do I get to use SubSonic with IQueryable but I get to learn T4.

However your brilliant syntax eludes me when I try to delete , or update a row. Can I get an example? I was expecting to be able to call update or delete by passing in the table object: db.Products.Update(product).

Gravatar
Yogesh - Friday, November 07, 2008 - There is a bug in Provider.tt:

Line 93 should be:

return new Select(DataProvider, new Aggregate(colName, AggregateFunction.Count)).From(tableName).ExecuteScalar();

instead of:

return new Select(DataProvider, new Aggregate(colName, AggregateFunction.Avg)).From(tableName).ExecuteScalar();



Can't we add a no parameter Count<> method which just returns the count of the query, like:

public object Count()

{

return new Select(DataProvider, new Aggregate("*", "RecordCount", AggregateFunction.Count))

.From(typeof(T).Name).ExecuteScalar();

}

Gravatar
Yogesh - Friday, November 07, 2008 - Agreed. :)
Gravatar
mikkel - Saturday, November 08, 2008 - when i run Classes.tt it only generate empty classes like

public class Users { }

insted of

public class Users

{

public String Username;

public String Password;

}
Gravatar
robconery - Monday, November 10, 2008 - I think this might be a limitation of VS Express - which I didn't know about

:(. If you're not using VS Express, I was able to get this to work here by

file/new/web application and dropping the TT files into the root.
Gravatar
hrvoje - Saturday, November 08, 2008 - thank you very much Rob for this! I was really looking forward to v3
Gravatar
Ibleif - Saturday, November 08, 2008 - Is it possible to "join" the queries? Something like this....



var products = from p in db.Products

where p.Category.Name == 'My lovely category'

select p;

Gravatar
Subnus - Saturday, November 08, 2008 - i would be nice to set the namespace in connection.tt and have it apply in the other .tt files



because i don't / can't name me provider ( subnus ) the same as my namespace ( Subnus.MVC.Data )



if i do visual studio crash
Gravatar
Nikolai - Monday, November 10, 2008 - I must be missing something: what and where do I need to change to use Oracle's ADO.NET providers? Otherwise: looks really nice so far!
Gravatar
hoehler - Tuesday, November 11, 2008 - Hi Rob,



Great job, thanks for sharing this.



For some reasons (please don't ask why) I have a table named "user". So the queries fail with a "syntax error near by the keyword user". Adding brackets (eg. "[user]") could be a solution.



Thomas
Gravatar
cowgaR - Saturday, November 08, 2008 - you...YOU... Y O U !!!



the release is sooner than you've promised.... your last day at Microsoft or what? I see you've even written an epilogue blog entry not to get fired straight away...boss praising and such goodies =)



congratulation to 1st public release of LINQSonic... I am a little dizzled about the provider and whole factory model though...

does it mean I need to get ADO.NET providers myself to support e.g. postgre database?



or will they ship with subsonic?

thanks
Gravatar
cowgaR - Saturday, November 08, 2008 - can you elaborate on this (making life difficult)?

I am not a native english speaker but does it mean you don't want us to completely depend on this "extra" stuff?



e.g. to use it just when necessary...



or was it humour? ;)
Gravatar
Jim - Monday, November 10, 2008 - AFAIK, T4 templates are not available for Visual Web Developer 2008 (the free version). So, it seems this will only work with Visual Studio 2008 paid versions.



I guess it makes sense to use the existing functionality in VS2008. But it was nice to be able to use Subsonic 2.x with the free versions.
Gravatar
daigoba66 - Wednesday, November 12, 2008 - Any chance of releasing the source code for this?
Gravatar
Jfar - Monday, November 10, 2008 - This. is. the. shit. Period.



Rob, you've made my ORM-y choice for any future projects really easy to make.



:D



Gravatar
cwbrandsma - Saturday, November 08, 2008 - I'd like some more information on the provider model changes you mentioned. I'm working with a non-standard database and will probably have to write the provider myself, so any help would be great.
Gravatar
jf26028 - Saturday, November 08, 2008 - I am seeing the same result. It appears that the datatable columns has 0 DataRows, but the correct number of columns in the columns property.



columns.Rows == 0

but

columns.Columns.Count == 18



Jesse
Gravatar
Justin - Saturday, November 08, 2008 - When you import an extension method namespace it adds intellisense to all the objects those methods are for. So if you're in an area where those methods are not needed they just clutter up your intellisense.
Gravatar
Slava - Saturday, November 08, 2008 - So, why use SubSonic 3 and not Linq to SQL or Linq to Entities? when is it better? when is it worse?
Gravatar
cowgaR - Sunday, November 09, 2008 - I don't know if PostGreSQL directly supports ADO.NET 2.0 data provider itself, but I found some open-source (free) provider project which I think I can use wich Subsonic:



npgSql

http://pgfoundry.org/projects/npgsql/



so I assume that all that is needed for me is to implement IDataProvider myself, which shouldn't be a nuclear science, and I am free to use SubSonic 3.0 on postgre databases, or not? =D



only other provider that I found was a commercial one from DevArt:

http://www.devart.com/pgsqlnet/



but I see no reason to pay for it (and there's some bad posts on forums about their "knowledge of developing" sqlite provider that Robert Simpson put big effort to) but that is just my oppinion, it might be super-performant ;)
Gravatar
cowgaR - Saturday, November 08, 2008 - thanks for explanation...



the pros, like myself, don't use intellisense at all.

quick look to library is sufficient to know _all_ what is required (sometimes we don't even need Rutz reflector, we guess many things just from the hex view of a dll)



... but it makes sense for you I see ;)
Gravatar
Justin - Saturday, November 08, 2008 - sometimes I wonder why I bother
Gravatar
jongalloway - Saturday, November 08, 2008 - Congrats, Rob! I know how long you've been working on this, and it shows. This is such a lightweight, elegant system that really leverages .NET 3.5 and LINQ.
Gravatar
robconery - Saturday, November 08, 2008 - Thanks Mikkel - any help you can give me here would be appreciated. TT files can be debugged like any code file - or you can rip it out and test it in a Console app.
Gravatar
robconery - Saturday, November 08, 2008 - You can do this with the templates if you like - reading FKs from Connection.GetSchema() is pretty simple :). I haven't included it here because that's ORM space and I'm not ready to take it there.



However this was my point above - anyone can craft a system on top of SubSonic 3 using the T4 templates :). So if you want to take a swing at it that would rock!
Gravatar
Nathan - Monday, November 10, 2008 - This looks great! Thanks!



I know this is still extremely early, but are you anticipating compatibility with mono 2.0+? I've recently started using mono for asp.net and 2.1 works great. I have a feeling once LINQ becomes available in a stable mono release, then it might be a non-issue. Thoughts?



I think you might have a lot of leverage vs EF if they truly deprecate L2S like they're talking.
Gravatar
robconery - Saturday, November 08, 2008 - Yep - that is correct. I don't know if PostGres supports the data factory, but if they don't you can implement IDataProvider for PostGres. I think they do support ADO.NET 2.0 - most every provider does.



All's well with work :)
Gravatar
robconery - Saturday, November 08, 2008 - Have a read about ADO.NET 2.0 (link is above) and System.Data.Common. If you use this namespace (using DbConnection, DbDataReader, DbCommand, etc) you can effectively write platform agnostic code and all you need to do is change your providerName (it's another secret in .NET).



If your DB won't work, you can implement IDataProvider (I think) which is all of 11 methods (nice and light). That's the hope, anyway.
Gravatar
robconery - Saturday, November 08, 2008 - I'll leave that up to you :). I'm not in a competitive position (nor have I ever been) with MS, I just like to leverage what they've done and make it rock :).



in this case I'm trying to make the LINQ experience a bit more transparent - allowing you to work up the code as you like with the T4 templates.
Gravatar
robconery - Saturday, November 08, 2008 - LOL cawgaR - I had thought the "I only work in Notepad" thing sort of died off :). Let's hope your boss isn't reading this :) he might wonder why he's paying you to stare at Reflector :):):).



Notepad FTW!
Gravatar
robconery - Saturday, November 08, 2008 - You can do whatever you like - that's the point :). In Connection.tt you can make a nice method called "GetSubnusNamespace()" and have it do whatever you like :).



It's all up to you.
Gravatar
Ibleif - Tuesday, November 11, 2008 - I don't get any properties at all. All my classes generated are empty? ... and the same problem with my structs.tt



Any help ?
Gravatar
Martin Nyborg - Saturday, November 08, 2008 - Is this working with sql express 2008? and how do you build the code?



Gravatar
robconery - Saturday, November 08, 2008 - Hi Martin - I would imagine it does, the code is completely provider independent. The templates can be setup however you like.



I'm using T4 templates

http://blog.wekeroad.com/blog/make-visual-studio-generate-your-repository/

Gravatar
Calixto - Monday, November 10, 2008 - Someone can tell me if VS2008 supports tt files in Web Projects?

I have the Team Version and tt files only works in Console or ClassLibrary projects.

When I create tt files in WebApps nothing happens, even out of App_Code directory.

(In the Professional Version the same thing happens)
Gravatar
roberto321 - Sunday, November 09, 2008 - Great stuff,



I was wondering if you could discuss the situation between subsonic 2.x and subsonic 3 in terms of moving forward, will subsonic 2.x stuff be worked upon for example I know there are many key outstanding bugs and time is limited between you guys and now with subsonic 3 being worked upon what do you envisage will happen to subsonic 2.x etc



Thanks for your time looking forward to using Subsonic 3.0
Gravatar
robconery - Wednesday, November 12, 2008 - Just need an "Oracle" template ... you game?
Gravatar
Martin Nyborg - Saturday, November 08, 2008 - Yes it is working with 2008

But I still don't know how to generate the code
Gravatar
Ibleif - Tuesday, November 11, 2008 - I was missing the connection-string inside my app.config.

It was not enough having it in my connection.tt



It would be nice only setting it once.
Gravatar
robconery - Tuesday, November 11, 2008 - As of now you can change the templates to do what you need them to do. That

said - I'll see what I can do here.
Gravatar
robconery - Tuesday, November 11, 2008 - I'm really trying to get the point across that all the naming issues can be

resolved quickly and easily by changing your templates. In your case, you

can to this:

tableName=tableName.Replace("user","[user]");



That will fix :)
Gravatar
robconery - Wednesday, November 12, 2008 - Yep - see my new post :)
Gravatar
wayde - Wednesday, November 12, 2008 - What happened to migrations? I like that feature but I don't see it in v.3
Gravatar
robconery - Monday, November 10, 2008 - Hi Jesse - the ORM part is coming, but right now you need to ....

db.Delete.From().Where("ProductID").IsEqualTo(1);



I'll fix this up :). Looks like "Totem Code"
Gravatar
robconery - Tuesday, November 11, 2008 - I should add here - the app.config stuff isn't used in code generation- only by your application. VS 2008 uses the T4 templates to render the code and runs in a completely separate space than your app - so reading the App.config is a bit difficult.



Anyway - I'm still puzzled as to why it all of sudden started to work. I've seen this happen and I'm wondering about locks...
Gravatar
Ibleif - Tuesday, November 11, 2008 - You are right... my bad. I can safely remove my app.config and it works fine now. I have no idea what was going on before.



Now that I do have your attention... How do I use the aggregates with "criterias" on?



db.Count(p => p.ID) ... and if I would like to only count the products with Price > 100 ?
Gravatar
cowgaR - Tuesday, November 11, 2008 - I assume you need to get oracle ADO.NET v2.0 provider (or 3.5 if you can find it) so you can connect to Oracle databases.

Google gave me 2 quick choices, official one straight from the oven I haven studied:

http://www.oracle.com/technology/tech/windows/odpnet/index.html



and the one I mentioned already, DevArt's developed provider, which I would like to sleep with straight away - so much I like their marketing info, Entity framework support and free ironing of my whole laundry during weekends:

http://www.devart.com/oranet/



which one of those is better is upon you (maybe some 3rd I haven't found), which one is better for subsonic 3.0 is upon your own tests =)



finally, you need to change providerName value in connectionStrings to your choosen provider and pray a lot...



I think it would be sufficient for me, sinners like you needs to try and pray a little harder though
Gravatar
robconery - Tuesday, November 11, 2008 - This is code (as I keep saying) that you can change yourself. If you look in

the Provider.tt file, you will see where I'm generating this stuff. All you

need to do is to change out the return value from object to SqlQuery, and

then instead of returning ExecuteScalar, you return the Select that is

built.

I'll make that change...
Gravatar
Todd - Tuesday, November 11, 2008 - I'm trying to use the templates with a MySql database. The Provider template worked fine but the Classes template generated empty classes with no fields.



I toyed with the template and it appears that Connection.GetColumns isn't returning any records. I'm using version 5.2.3 of the MySql Connector. I'm gonna start debugging the template but, off the top of your head, do you know what might be happening?



Thanks.
Gravatar
Yogesh - Tuesday, November 11, 2008 - Replac e GetColumns with this"

DataTable GetColumns(string table){

DbConnection connection = GetConnection();

string[] restrictions = new string[4] { connection.Database, null, table, null };

return connection.GetSchema("Columns",restrictions);

}



Check again, I think it will solve the issue.
Gravatar
jmarkhus - Monday, January 19, 2009 - Hi Rob,



playing with subsonic, mysql and c#. error message brought all fun to dead halt.

when i tried;



user.update(2, "jm","jackass", "marcus", 1);

assert.areequal(1, ulevel);



my test failed!! i was trying to test the update method by changing ulevel from 3 to 1.

the error message was from the mysql server alleging that subsonic sent a wrong

update query.



is there a way to update another way? by the way, is there no way for me to change

which dotnet connector i am using? (to a ore recent version).



what is / where is your email?



thnx
Gravatar
Jean - Wednesday, November 12, 2008 - Rob!



This is awesome news! I used Subsonic 2.0.3 on a previous project of mine and it was easy to use and set up, on top of which it doesn't create code bloat like Nettiers.



Looking forward to putting it through it's paces. :-)
Gravatar
Todd - Wednesday, November 12, 2008 - I had to break out Reflector to see what MySql.Data was doing. The restrictions array needed to be reordered, it needs to be:



string[] restrictions = new string[4] {null, ProviderName, table, null};



I also noticed that the column name is different when looking for the Primary Key. Instead of "constraint_name" it's "index_name".



I'm really excited about the new changes Rob, great work!
Gravatar
Todd - Wednesday, November 12, 2008 - I updated the templates to work properly with MySql. Two changes were needed: the order of the restrictions array and the column name used to look up the primary key. Really odd that these changes were needed though, I thought the Schema implementations for DbConnection were supposed to be standard across data providers, oh well.



I can upload the updates if anyone is interested.
Gravatar
robconery - Wednesday, November 12, 2008 - Tell ya what - send them to me and I'll add them as options :). Thanks for

this - that's really weird that the order is different!
Gravatar
wayde - Wednesday, November 12, 2008 - +1 for a sonic screencast showing how to set up v.3 and demonstrate working with the T4 templates to customize the code gen.



btw, thanks for putting this out! I really like the direction you are going here and I'm interested to see what kind of ORMs pop-up that will run on subsonic as a result.
Gravatar
wayde - Wednesday, November 12, 2008 - Questions/Issues:



1. I'm using this in an ASP.NET MVC Web application and none of the T4 templates run unless I right-click ea. one and select "Run Custom Tool." This gets to be a pain after awhile ... so is there any way to correct this so they automagically run when the project is saved and/or compiled?



2. There is no code genereated by the Connection.tt ... is that correct?



3. Is there any reason that the classes generated by Classes.tt are not partial?



4. Why do we have to specify the connection string in Connection.tt if we already have done so in the web.config?



Thanks again.
Gravatar
robconery - Wednesday, November 12, 2008 - Hi Wayde - the templates only fire when you:

1) Add them to your project

2) Change the text

3) Right-click run.



In terms of "pain" - try writing that code yourself ;).



Connection.tt doesn't generate code, no.



Partials are coming next...



The reason you need to specify a connection string is that the App domain

that T4 runs in is completely separate than that of your project.
Gravatar
robconery - Wednesday, November 12, 2008 - Yep - eventually.
Gravatar
robconery - Wednesday, November 12, 2008 - This is a Preview - haven't added those in yet.
Gravatar
wayde - Wednesday, November 12, 2008 - Ok, last question of the day (from me at least) ...



How difficult would it be to update your MVC addin to work against preview 1 here? I didn't see the source available for the former so I'm not sure how much work would be involved ... but being a Rails guy who likes Subsonic and what I see in the mvc addin ... that is exactly what i'm lookin for.



thanks
Gravatar
wayde - Wednesday, November 12, 2008 - Ok that makes sense.



I'm guessing something like your mvc addin would be a better spot to include code to execute the templates for a given db ... or even just a particular model ... along with all the other code gen it does for your mvc app.
Gravatar
ptutt - Wednesday, November 12, 2008 - one of my gripes with subsonic 2.1 is that it the data objects are not compatible with datacontract serialization in WCF. I had to create my own lightweight DTO classes and customise the subsonic code generation to use custom templates. Anything in 3.0 for me regarding this???
Gravatar
Nikolai - Wednesday, November 12, 2008 - Yeah, been there, done that. The problem is though that many things in SubSonic's templates are hard-coded for MSSQL, especially types' conversion, column order (for column names) etc. Therefore I concluded that Oracle is not supported yet, but I'd like to hear an "official" word on this.
Gravatar
robconery - Monday, January 19, 2009 - Have a look at the alpha here:

http://blog.wekeroad.com/blog/subsonic-3-alpha-is-ready/



Also there is a mailing list for 3.0 Alpha issue (link on the article).

Finally - if you can me a SQL Script to repro your DB I'll do my best to fix

the issue (send using the group list).
Gravatar
JT - Tuesday, November 25, 2008 - Just a tip: if you update the database schema and would like those changes to be made to the generated classes, just open up Classes.tt in VS and hit the save button. It will regenerate the classes for you. No need to keep dropping in the file. This works in VS 2008, not sure about 05.
Gravatar
robconery - Tuesday, November 25, 2008 - Or right-click and hit "Run Custom Tool"
Gravatar
Fero - Wednesday, December 17, 2008 - Where are the MySql templates I can't generate classes.
Gravatar
rome - Thursday, January 22, 2009 - I receive an error when Visual Studio try to generate cs files from tt files.

I use a MySQL DB and I added MySql.Data.dll in my /bin directory

I added the code to switch DB provider in my Web.config





This is the error :

Error 2 Running transformation: System.InvalidOperationException: The ConnectionString property has not been initialized.

at System.Data.SqlClient.SqlConnection.PermissionDemand()

at System.Data.SqlClient.SqlConnectionFactory.PermissionDemand(DbConnection outerConnection)

at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)

at System.Data.SqlClient.SqlConnection.Open()





Why it invoke System.Data.SqlClient.SqlConnection and not MySql.Data.MySQLConnection ???

using System.Data.Common is in my page



thanks

Gravatar
Bill Forney - Sunday, January 11, 2009 - I wanna see this used with Azure. :) I'm playing with that stuff lately.
Gravatar
bungei - Tuesday, April 21, 2009 - what is this error plz help Error2An object reference is required for the non-static field, method, or property 'OARS.Model.Service.System.get'C:oarsProjectsOARSOARS.ModelTablesService.cs51115OARS.Model
Gravatar
Dmitry - Monday, June 01, 2009 - Man, THANKS A LOT !!!! You and your baby are really ROKS !!! Pls go ahead dont stop :D Best regards !