6

I would like to know if there's a good ORM that can automate some of the manual work I have to do right now. Our application uses stored procedures heavily, meaning that any interaction with the database goes through a stored procedure.

Right now, I have to call stored procedures in the traditional way, and it's quite tedious. Is there an ORM that does a good job at dealing with stored procedures that:

  1. Have input/output parameters that are structured, meaning table valued types
  2. Easily allow for output parameters to be user-defined types, both scalar and table valued
  3. Return multiple record sets
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Candide
  • 30,469
  • 8
  • 53
  • 60
  • possible duplicate of [Which ORM is the best when using Stored Procedures](http://stackoverflow.com/questions/687762/which-orm-is-the-best-when-using-stored-procedures) – jgauffin Jul 09 '11 at 14:21
  • @jgauffin: I think this question is valid after 2 years. Think of all the new stuff since March 2009 – gbn Jul 09 '11 at 14:38
  • It's not a duplicate. I'm trying to figure out if an orm or adapter can do a proper job with table valued in/out parameters, while doing a lot of what ado.net does. – Candide Jul 10 '11 at 02:53
  • 1
    There is no orm that would give you a clean and concise way of passing in\out TVPs. Dapper could be adapted to support this but you would need to add a layer. I stayed away from TVPs cause perf is not great and it requires SQL Server – Sam Saffron Jul 10 '11 at 04:26

3 Answers3

8

Dapper has fairly extensive stored procedure support.

The trivial:

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

It 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 and return parameter support
  3. An extensible interface for database 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 allows 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 parameters and other database specific features.

You're using it now on Stack Overflow...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
gbn
  • 422,506
  • 82
  • 585
  • 676
  • 3
    I spent quite a bit of time learning how to use Dapper, and seeing it in action is impressive. I found that the table valued parameters are not easy to work with, because tvps are sql server specific, and Dapper tries to stay generic. There's an example in Tests showing IntDynamicParam, but that's for one parameter, when I do want to keep the ability to add other parameters as well. So, there isn't a quick fix, and an adapter specific to sql server would take quite a bit more work. – Candide Jul 10 '11 at 02:47
  • @Roland tvps have a very odd API. Wrapping it up in a tidy helper is not that easy, if you are passing in a IEnumerable there would need to be a way to detect the name of the type. I'll see if I can extend the test can you raise a ticket so I can track – Sam Saffron Jul 10 '11 at 03:53
  • 1
    One possibly major caveat with Dapper and Stored Procs is that it does **not** support passing a rich object in as the criteria (e.g. you could pass in `new { CustomerId = 42 }` but not `var cust = new Customer { CustomerId = 42 }` and pass in the `cust` variable; Dapper will try to parse *every* property of the object as a parameter to the stored procedure, not just the properties you set. – Wayne Molina May 18 '12 at 12:26
  • @WayneM: one reason we don't use dapper. We need full-on O-R mapping. Thanks – gbn May 18 '12 at 12:38
2

Check out the Entity Framework.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
FiveTools
  • 5,970
  • 15
  • 62
  • 84
  • EF is quite nice and it does almost everything I needed except for the table user defined types. The same drawback is in linq2sql as well. – Candide Jul 09 '11 at 16:43
  • On the other hand, only EF4 allows you to specify stored procs for inserting, updating, deleting entities. Also, EF4 allows you to easily create new "complex types" in its mapping file for stored proc results that don't match an existing entity (or collection of entities) – marc_s Jul 09 '11 at 21:34
  • @marc_s but in some ways the limitations of your ORM are defining the style of TSQL coding you are allowed to follow. cutting out support for TVPs can complicate insertions of batches especially if you want elaborate duplicate handling. – Sam Saffron Jul 10 '11 at 05:43
1

If memory serves, LINQ to SQL has the ability to map methods to stored procedures. When you create a LINQ to SQL context inside Visual Studio, you can connect your database and drag and drop the tables into the design view. It will detect any stored procedures and generate the necessary methods inside the model objects.

See Scott Guthrie's blog post LINQ to SQL (Part 6 - Retrieving Data Using Stored Procedures) .

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jason Miesionczek
  • 14,268
  • 17
  • 76
  • 108
  • Tried it and found out that it doesn't work for user defined types, in particular table types. – Candide Jul 09 '11 at 14:14
  • the end of that blog post mentions support for user defined types – Jason Miesionczek Jul 09 '11 at 14:21
  • Maybe I'm missing something, but I think it's referring to user defined functions. Also, it works if a defined type is rather primitive (the equivalent of typedef), but not for more complex types. User defined table types in Sql Server are not available for linq2sql, I read several posts claiming this. However, thanks for the reply. – Candide Jul 09 '11 at 16:42