12 ms·
Trust me, you don't want EF--no matter how many times they say "vNext is gonna be great!!1 for real this time." Consider a micro-ORM like dapper[1]. [1] https:
by justinmk 10y ago
Trust me, you don't want EF--no matter how many times they say "vNext is gonna be great!!1 for real this time." Consider a micro-ORM like dapper[1].
[1] https://github.com/StackExchange/dapper-dot-net https://github.com/StackExchange/dapper-dot-net
- gnaritas 10y agoYes yes yes, but better yet, write your own. Micro ORM's are "micro", it's pretty trivial to create something better than Dapper and there's no framework in the world better than your own, to you, because there won't ever be anything to complain about, just mold it to work exactly how you like. Dapper.. var dogs = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid }); yuk, I prefer var dogs = Dog.FindAll(And(IsNull("Age"), Equal("Id", guid))); A touch of generics done properly, a bit of reflection, a static import, and you can do much better than onnection.Query<Dog>. Write the API you want, implementing what is basically an active record without relationships is not terribly difficult and will pay off for years to come in your own code. Edit: Dappers API is ugly as fuck, that's an immediate non-starter for me, and the cost of reflection on loading objects is the wrong problem to be optimizing and would only show up in an absurd micro benchmark intended to show off speed that doesn't matter, it's small compared to the execution time of the queries. If you like it, use it, but lets not pretend it's so much effort it isn't worth redoing. It's certainly not the end all be all of ORMs.
- justinmk 10y agoNo, there's no (technical) reason to redundantly solve the problems that dapper has solved. In particular the emitted IL which avoids costly reflection is not something many people will correctly re-implement. > A touch of generics done properly, a bit of reflection, Dapper avoids reflection, its performance is very close to a hard-coded SqlCommand.
- gnaritas 10y agoIf you're worried about the speed difference between reflection and a hand written command, you're spending your time in the wrong part of the code. Reflection isn't the bottleneck, the database is, by far. Yes, if you speed test the difference between reflection and handwritten, it'll look slow, but such micro-benchmarks are unrealistic of production code. If you look for slowness you'll find it everywhere you look, but if you profile real code you'll find the only slow code that actually matters and you'll find that database IO is the bottleneck generally.
- mythz 10y ago> var dogs = Dog.FindAll(And(IsNull("Age"), Equal("Id", guid))); That's pretty ugly and not idiomatic for .NET which favors using typed LINQ providers for data querying. We develop OrmLite, a fast, code-first POCO ORM which lets you use LINQ to query and map to clean POCO's so you could instead query the above with: var dogs = db.Select<Dog>(x => x.Age == null && x.Id == guid); You can see more OrmLite features and try them out "live" with just a browser with the Interactive Tour on: http://gistlyn.com/ormlite http://gistlyn.com/ormlite
- gnaritas 10y ago:) Well, it's pretty ugly now that expressions exist, however prior to expressions it was quite nice since S expressions is all they are and I've had this for nearly a decade in .Net, long long before such niceties like expressions existed. And I'll just bolt expressions into my library when I feel like it and type this var dogs = Dog.FindAll(each => each.Age == null && each.Id == guid); rather than relying on an external dependency that doesn't work the way I want. The need to do this... db.Select<Dog> Use generics at the method level, I find intolerably ugly when you could have created db with said type and have access to an already typed API. What you're doing there, I personally consider bad design and would refuse to use. When I use a typed list... I don't go someList.Add<Thing>(aThing) Because the decision to type the list was done at list creation time. Forcing me to pass a type on every call to the db, less than attractive. The best uses of generics don't look like you're using generics because you only have to do this once class Dog : Persistable<Dog> {} To have a perfectly typed class side API that doesn't shit generics all over the client side code. The T is specified once and only once, and never seen again and now all the Select/Save/Delete/Create methods no longer require the client to constantly type <Dog> every time they touch your lib. In all fairness however, it would be trivial to wrap your lib in a persistable template and achieve exactly the API I wanted, should I ever desire to do so. Which is actually a much better argument for using your lib than any you've given.
- mythz 10y ago> Use generics at the method level, I find intolerably ugly Then you shouldn't be using .NET, generic methods are extremely common and especially elegant here since it can work with any POCO which can also be reused elsewhere in any library that works with POCOs. The Generic method is what enables the Typed API without adding any artificial artifacts and wrappers. It's intuitive as to what the lambda is typed to and what value is returned - it's definitely more idiomatic and much preferred over Active Record implementations. In your Example `Dog` ends up being a .NET 1.0-style non-serializable bloated Active Record inheriting from a heavy base class that's non-reusable and coupled to your implementation that you're forced to create for each Type you want to use. It's also not clear what DB connection is being used, what its life-cycle is and whether it's being reused across different types, how you can create transactions spanning multiple types, etc - in Micro ORM's its clear, you use the same db connection to query any Type. There's a reason why most modern Micro ORM's are mapping to clean disconnected POCO's and don't force unnecessary wrappers for legacy inhibitive abstractions like this.
- gokhan 10y agoYou still don't need to write your own implementation. DapperExtensions got you covered, see predicates. They're not visually pleasing, but so do your implementation. By the way, you got a nasty NIH syndrome to tackle, just saying.
- gnaritas 10y agoI've had my own micro ORM before any of those other ORMs existed or the term micro ORM was a thing, so one can hardly call that NIH. In fact there weren't any ORM's in .Net at all when I wrote mine. I love using good external libs, use them all the time. What I have is lots of experience with shitty ORM's and a fascination with the ORM problem that's led me to write several ORMs of my own just for the fun of it. Frankly I think it's one of the great teaching programs you can write, you'll learn a ton writing an ORM if you've never done it before. Thanks for the tip on DapperExtensions, I'll take a look.
- taspeotis 10y agoPick the right tool for the job. EF works great for us for OLTP workloads. OLAP workloads: choose something else.
- baconner 10y agoYeah I don't see why you would want any kind of orm for olap, not just EF.
- jsmith0295 10y agoI tend to prefer things which are more lightweight, but my coworkers don't. I'm mostly wanting to pitch this as a better alternative to Spring Boot and JPA.
- matthewking 10y agoCurious what shortcomings you're finding in Spring Boot that Dot Net Core would solve?