7

I have Business objects (DEVELOPERS WRITE) and some SPROCS (DBA WRITE)

Can anyone recommend a good object mapper to deal with this kind of setup.

I tried codesmith and nhibernate and had trouble. I do not mind if my ORM is free or paid.

Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
Jojo
  • 319
  • 3
  • 10
  • 2
    I don't see what's so bad about sprocs. Sometimes they are just the thing. How'd they get such a bad name? – Cheeso Mar 27 '09 at 04:32
  • Well there are a lot of people that don't like them. They are great when it comes to tweaking a query for performance, but a nightmare for maintenance, like one of my projects has 400+ sprocs.... Thank goodness for schema compare in VSTS. – Jojo Mar 27 '09 at 14:11
  • I'm looking for similar solutions since our new project tech lead is *insisting* that all code-to-database interactions be through stored procedures. Every CRUD operation. Every query. Everything. But, he wants to have a completely generic DAL :-) – CMPalmer Jun 01 '09 at 20:08
  • @Cheeso It's not sprocs' fault; they just do what they're told. Sprocs just don't have protection under HR. Imagine you're debugging some thing in Gordian Knot 3.1.5 that calls `sp_GetUserById`. The view model, controllers, and services are all doing their thing and passing their tests (you have tests, right?). You check the data; it looks fine. "Sonofa...." you mutter as you load up SSMS again. There it is! Not only is there business logic in a sproc that was just supposed to `sp_GetUserById`, but it conflicts with the new feature that was released last month. Good luck skirting that blame! – CaptainMarvel Jun 18 '19 at 14:18

9 Answers9

7

SubSonic has excellent support for sprocs. It will wrap each one in a helper method and you can retrieve strongly-typed collections or entities from the results if you want. I show a way to do that in this blog post. As long as your sproc returns the same schema as SELECT * FROM TableName would, it will work with your SubSonic entities.

As far as generating classes based on your db, SubSonic generates partial classes so you can extend them as needed. You could also do mappings from the SubSonic generated classes to your actual model.

John Sheehan
  • 77,456
  • 30
  • 160
  • 194
  • just like linq2sql - how about multiple result sets in 1 procedure, possibly mapped to entities? :) – eglasius Mar 26 '09 at 23:03
  • I believe you can only load multiple result sets to datasets. – John Sheehan Mar 26 '09 at 23:07
  • 1
    Subsonic has some serious perf issues around materialization – Sam Saffron Jul 10 '11 at 04:29
  • care to offer a better answer to the question? kind of strange to go around dumping on Subsonic in ways unrelated to the question without offering an alternative. – John Sheehan Jul 10 '11 at 06:30
  • ok I replied http://stackoverflow.com/questions/687762/which-orm-is-the-best-when-using-stored-procedures/6645870#6645870 ... subsonic is not going to give you multiple record set support, input/output params support and so on. – Sam Saffron Jul 11 '11 at 04:52
6

Disclaimer: I am the author of Dapper.


If you are looking for a simple object mapper that handles mapping procs to business objects Dapper is a good fit.

Keep in mind it ships with no "graph management", "identity map" and so on. It offers a bare bone, complete solution which covers many scenarios other ORMs do not.

Nonetheless, it offers one of the fastest object materializers out there, which can be 10x faster than EF or even 100x faster than subsonic in some benchmarks.


The trivial:

create proc spGetOrder
   @Id int
as 
select * from Orders where Id = @Id
select * from OrderItems where OrderId = @Id 

Can be mapped with the following:

var grid = cnn.QueryMultiple("spGetOrder", new {Id = 1}, commandType: CommandType.StoredProcedure);
var order = grid.Read<Order>();
order.Items = grid.Read<OrderItems>(); 

Additionally you have support for:

  1. A multi-mapper that allows you single rows to multiple objects
  2. Input/Output/Return param support
  3. An extensible interface for db specific parameter handling (like TVPs)

So for example:

create proc spGetOrderFancy
   @Id int,
   @Message nvarchar(100) output 
as 
set @Message = N'My message' 
select * from Orders join Users u on OwnerId = u.Id where Id = @Id
select * from OrderItems where OrderId = @Id
return @@rowcount

Can be mapped with:

var p = new DynamicParameters(); 
p.Add("Id", 1);
p.Add("Message",direction: ParameterDirection.Output);
p.Add("rval",direction: ParameterDirection.ReturnValue);
var grid = cnn.QueryMultiple("spGetOrder", p, commandType: CommandType.StoredProcedure);
var order = grid.Read<Order,User,Order>((o,u) => {o.Owner = u; return o;});
order.Items = grid.Read<OrderItems>(); 

var returnVal = p.Get<int>("rval"); 
var message = p.Get<string>("message"); 

Finally, dapper also allow for a custom parameter implementation:

public interface IDynamicParameters
{
   void AddParameters(IDbCommand command);
}

When implementing this interface you can tell dapper what parameters you wish to add to your command. This allow you to support Table-Valued-Params and other DB specific features.

Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
5

Subsonic has a flexible solution:

    class CustomerOrder {
        private string productName;

        public string ProductName {
            get { return productName; }
            set { productName = value; }
        }
        private int total;

        public int Total {
            get { return total; }
            set { total = value; }
        }

    }

Then:

List<CustomerOrder> orders = Northwind.SPs.CustOrderHist("ALFKI")
        .ExecuteTypedList<CustomerOrder>();

Subsonic is a solid "Swiss Army knife" style ORM.

David Robbins
  • 9,996
  • 7
  • 51
  • 82
2

Depending on the database Entity Framework, or NHibernate are likely your best options (examples in links).

Tracker1
  • 19,103
  • 12
  • 80
  • 106
  • No, Nhibernate does not work well with sprocs, unless I'm missing something. It requires items returned to be in a paticular order and have other limitations. – Jojo Mar 26 '09 at 22:33
1

The LINQ to SQL designer will give you type-safe sprocs as methods on the DataContext object. You can map those to objects for CRUD operations fairly easily.

In fact, I'm in the middle of doing exactly that.

Randolpho
  • 55,384
  • 17
  • 145
  • 179
  • The issue I have with LINQ to SQL is that Microsoft has pretty killed the product. And have everything behind Entity framework. – Jojo Mar 26 '09 at 22:21
  • @Joe not really, I don't have the link but there was another answer on it, and we got an update that there is a team with ongoing activities with linq2sql – eglasius Mar 26 '09 at 22:28
  • It would be sweet if you had the link, but I will google it and see if I can find it, last I heard it was transfered to the ADO team, which is a dead end. – Jojo Mar 26 '09 at 22:35
  • @Joe see Marc's reply in this answer http://stackoverflow.com/questions/653019/linq-to-sql-pitfalls/653201#653201 – eglasius Mar 26 '09 at 22:56
1

Since you've got a DBA writing the sprocs, I would think the best thing to do would be to work closely with him to figure out how to map the tables to objects, and how to structure the database so that it works with your domain model. There's nothing wrong with sprocs, they just require close collaboration between the developers and the DBAs.

Ideally, the DBA in question is part of your project team...

Adam Jaskiewicz
  • 10,934
  • 3
  • 34
  • 37
0

These days you might try Nfinity.Data, which has strongly typed support for stored procedures, including table-valued parameters (TVP), and out parameters. To read any results, you need to access a reader manually (it provides a reader abstraction for this).

I’m not convinced of the NHibernate or EF idea of mapping entities to stored procs, as their inner workings are indeterminate, i.e., can’t be verified in any way until runtime. It’s more declarative to just do everything in code, via a reader as above.

DvS
  • 1,025
  • 6
  • 11
0

The main issue I see with this, is that by going with SP you are automatically loosing lot of the flexibility you get when using ORM, specially on the retrieval of information. Because of this, I am sure you won't be able to use All of the features of most ORM.

For example, if you use linq2sql, you will have pretty much wrapper to the SPs. You can also map insert, deletes and updates of the generated entities to stored procedures. Where you loose a lot is on the retrieval of information, both because the queries are now fixed (and you might retrieve more information than needed i.e. extra columns - or create lots of SPs) and on lazy loading.

Update: I am more a linq2sql guy, but I would take a second look at the assumptions you are taking about NHibernate. In particular, I doubt it will force column order as it is configured with column names (see http://nhibernate.info/blog/2008/11/23/populating-entities-from-stored-procedures-with-nhibernate.html). It also supports something I don't know how to do with linq2sql: http://nhibernate.info/blog/2008/11/23/populating-entities-with-associations-from-stored-procedures-with-nhibernate.html. Note, I don't mean that last one isn't supported with linq2sql, just that I don't know how to ;)

hazzik
  • 13,019
  • 9
  • 47
  • 86
eglasius
  • 35,831
  • 5
  • 65
  • 110
0

I like the way the Entity Framework handles sprocs right now. You can associate sprocs with the crud operations of an entity, it even detects which sprocs match up with the properties of your entity. The one big downside right now is if you associate one sproc with an entity you must associate all the crud operations with a sproc.

This EF Sproc article has some great examples of how to use sprocs in EF and has some really nice Extension methods for it as well.

pete blair
  • 1,607
  • 1
  • 17
  • 14