Yes, that’s truth. World now has yet another ORM system written in .NET. Again someone (me) reinvented the wheel. Why?
Before you started abusing me, let me provide you with some insight.
Of course there was need for this ORM to be born
I’ve been working with NHibernate for manner of couple of years. I would say team got used to it. Few months ago we’ve got challenge to integrate some of our code with legacy system. It is written in Delphi, but exposes some .NET stuff. Underlying data provider was legacy cache system (relational) covered with Delphi and bit exposed in .NET, also cache was capable of switching to SQLServer when in connected mode. When we decided to integrate our system with this legacy code we had to come up with solution that utilizes existing WCF (!) entities for mapping, solution that can call legacy code with correct select sql statements depending on connect mode and can handle update/insert/delete for the object graphs utilizing legacy interfaces.
Long story short, we ended very much with these three methods. Some other methods are also available, but I’m showing this for more rush:
This doesn’t look like exposing a lot of possibilities. We had option to go with naked SQL, than mapping from DataTables to entities reading data with DataReader. And all manual. Isn’t it boring and too-oo-oo much code?
It is fun to work on ORM, so why not take it further
For me it was really nice work to make that whole reflection and data access working smoothly. So I tried to have my code as much abstract as I can so it can be isolated somehow from that legacy and separated code for my personal project very early. Some of the features I had to recode at work, some at home. Instead of “IntegrationDataAccess” I wrote simple AdoDataAccess over mine IDataAccess and got it more or less completed.
I think it is part of my learning curve, to write this project. I’m learning what it means to start something open source, how to use yet another source control. Playing with hardcore reflection and other not-business logic code is real fun.
Another thing why I would like to make it open to the world and not mine home-hidden project is being exposed to more job opportunities. When you are at interview you often have no code to show, because all you’ve written is production and you signed papers forbidding you to show that code.
CustomORM is tiny ORM system written in .NET. CORM is slightly bigger than so-called micro-ORMs and much smaller than NHibernate. It has its uniqueness.
Features at glance:
POCO (real POCO without any “virtual” constraints or attributes)
Mapping much like FluentNH
Very light, thus faster
No syntaxes to learn (nothing like complex criteria or another version of sql)
Source code in your project you can debug, and change quickly
Now, let me show you some code
Sample fetch
Here is how select works:
Criteria criteria = CreateCriteria(typeof(Customer), "c")
.AddEntity(typeof(Order), "o")
.AddEntity(typeof(Employee), "e")
.AddSQL(
@"left join Orders o
on c.[Customer ID] = o.[Customer ID]
left join Employees e
on e.[Employee ID] = o.[Employee ID]
where c.[Customer ID] = @customerId")
.AddParameter("@customerId", customerId);
List<Customer> customers = ExecuteCriteria<Customer>(criteria);
As you can see you add type of entity to take part in join, assign alias to it and then write old known SQL. In the end you get nice collection of objects. No root transformations to be applied.
To get started all setup you need is basically two things: derive you own Repository class from RepositoryBase and add bootstrap code at start of your app similar to this:
// Let CORM know where your mappings live and that's mostly it
MagicMapper.ScanForMappers(Assembly.GetExecutingAssembly());
// Initialize AdoDataAccess or (advanced) implement your own IDataAcces
var s = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"];
var ceDataAccess = new AdoDataAccess(s.ConnectionString, s.ProviderName);
// You are ready to use you repository, it already has Fetch<T>, Save, Delete
var customerRepository = new CustomerRepository(ceDataAccess);
Hope it doesn’t look like much code.
What is at codeplex now and what’s next?
As for now I have CRUD operations tested on Northwind SqlCe database. I verified that fetching 91 customers (2000 db records) is 2-3 times faster than NHibernate.
Project still lacks very much in transactions/sessions/concurrency and completely doesn’t have caching (I don’t think it should ever have).
Project has bad code coverage and probably isn’t ready for community review until I polish it. But anyway sharing this with you because someone has to kick-me-off.
If you still would like to take a look at some code please start with CustomORM.Examples => Program for usage code and for engine code go to CustomORM where most of the heavy logic lives in RepositoryBase and EntityToTableMapper.
Depending on feedback and my mood I will decide if it worth investing more of mine time or not.
Also, looking at the select example, I just don't understand why you have to have column and table names both, in your mappings and in your queries (looking at joins and where clause)? I mean, we use mappings to hide the database schema and let us use our entities in queries and here it seems like it's a pretty leaky abstraction – to use your mapper I have to know about both, the entities and the schema. I'd much rather an API similar to LINQ – but lighter, something like:
I realize it's a bit harder to achieve, but it lets us have two advantages: 1) it's strongly typed – refactoring is much easier 2) keeps database schema details in mappings
Also, it looks like you can just build that strongly typed API on top of the existing functionality. :)
Hello gedgei. Sorry for my blog eating your generics.
Thank you very much for the comments.
1) As for using, you can do it right now. 2) As for LeftJoin(…) it is doable and I can/will add this feature. As for now let's assume that we already had SQL code, so it was easier to utilize it.
This website uses cookies. We'll assume you're ok with this, but you can opt-out if you wish.AcceptRead More
Privacy & Cookies Policy
Privacy Overview
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
Transaction handling using the "using" statement, with implicit rollback, would be much nicer. Just like NHibernate and other libraries do:
using(var transaction = BeginTransaction())
{
transaction.Commit();
}
Also, looking at the select example, I just don't understand why you have to have column and table names both, in your mappings and in your queries (looking at joins and where clause)? I mean, we use mappings to hide the database schema and let us use our entities in queries and here it seems like it's a pretty leaky abstraction – to use your mapper I have to know about both, the entities and the schema. I'd much rather an API similar to LINQ – but lighter, something like:
CreateCriteria()
.LeftJoin((c, o) => c.CustomerId == o.CustomerId)
.LeftJoin((o, e) => o.EmployeeId == e.EmployeeId)
…
I realize it's a bit harder to achieve, but it lets us have two advantages:
1) it's strongly typed – refactoring is much easier
2) keeps database schema details in mappings
Also, it looks like you can just build that strongly typed API on top of the existing functionality. :)
Hmm, the blog ate my generics :D
Hello gedgei. Sorry for my blog eating your generics.
Thank you very much for the comments.
1) As for using, you can do it right now.
2) As for LeftJoin(…) it is doable and I can/will add this feature. As for now let's assume that we already had SQL code, so it was easier to utilize it.
ibatis?
Nope, not "ibatis". I didn't even know about such system.