- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
#1) Yes, that code stinks...
#2) Generics are a pale comparison to proper templates. Consider a program for the computer to play tic-tac-toe. To make it determinate, the computer will always pick the top-most/left-most square that ties in the evaluation process. Using templates, it is possible to reduce this to 100% compile time, so that the actual code consists of nothing but "cout<<" statements to print the board after each turn --- Try that with puny generics.
Admin
Repository pattern is good but not always needed. EF basically is a repository pattern itself so you're wrapping the wrapper.
That code however, yikes.
Admin
From my understanding, templates primarily solve the problem of creating generic abstractions without requiring run-time type system overhead.
One consequence is that C++ is the only language I know with libraries that allow performing numerics with physical units safety without incurring significant runtime overhead – also compile time verification to avoid "volume plus area" type mistakes.
So yes, generics are much less powerful. Solving tic tac toe at compile time however, doesn't really demonstrate why you'd want to pay the cost for the power.
Admin
So... Have you even used Entity Framework before? Inheriting from
DbContext
not only is not a code smell, as far as I can tell it is the only way to actually use Entity Framework, as, to access the table types, you need to either defineDbSet<T>
typed properties on yourDbContext
derived type, or you need to override theOnModelCreating
method, and call themodelBuilder.Entity<T>()
method to enable the use of theSet<T>()
method. Attempting to use theSet<T>()
method without either defining a correspondingDbSet<T>
property or callingmodelBuilder.Entity<T>()
in theOnModelCreating
method will result in a runtime exception "System.InvalidOperationException: The entity type 'T' was not found. Ensure that the entity type has been added to the model."Most everything else in the article is on point, though there is a fairly narrow edge case where a generic repository type works well, such as when creating multiple CRUD pages for the multiple different entity types which would otherwise have the same code repeated, save for different entity types. But, even then, it really only makes sense within a single project, and not a system wide dependency.
Admin
Admittedly, it's been a minute- at least in the versions I used, you didn't do anything like what you describe.
Admin
You've just provided a perfect example of why Generic are preferred by many. I don't want my data structures to be able to play tic tac toe.
Admin
That was my experience as well. Coming from C++, it took me a while to wrap my head around C# generics, since they're evaluated at run-time instead of compile-time. A lot of my favorite C++ tricks just didn't work anymore, like creating type-specific instances of a template or even just using the compiler for type-checking.
Admin
What kind of compiler type checking didn't work for you? I've only really used generics with Java, but there the whole point is to provide static type checking and safe automatic casting, where otherwise you'd be passing around bare Object instances, with no enforcement of type constraints.
Admin
If the template is "playing" Tic-Tac-Toe, it's basically just macros that generate the entire game tree. Which is only possible because Tic-Tac-Toe has a tiny game tree. Theoretically you could also do the same thing with chess, but you'd run out of disk space for the executable.
Admin
Any type substitution system which can't play basketball is inferior.
Admin
You're right, here's what the documentation of DbSet <> says (https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext?view=efcore-5.0):
"Typically you create a class that derives from DbContext and contains DbSet<TEntity> properties for each entity in the model."
Admin
I think C++ causes permanent brain damage.
Admin
So is the real WTF the fact that everyone couldn't just use the class as intended and cope with the extra freedom of being able to specify a type in the method calls provided?
Admin
var carRepo = new Repository<Car>();
fooRepo.SaveEntity<Driver>(new Driver());
Um, you realize you have two different variables here, Remy?
Admin
I read all this and understood the words. Being that I dealt with programming with C, i probably would understand this reasonably well eventually. The issue for me is this is too far in "abstract theory" which is the far opposite end of the spectrum from where I am was as a programmer in C and Unix.
Admin
I think all of us realised that.
On a (mostly) daily post, it's reasonable for the reader to fill in the gaps. Took me about five seconds. YMMV.
Admin
It's more "framework" than "abstract theory."
I rather like the notion of Enterprise Framework, and one of my cow-orkers (out of a herd of five) has used it to good effect.
But it doesn't take "abstract theory" to make you question the idiotic idea of applying generics to methods within a generic type. Or to despair at the consequent plethora of concrete types that are instantiated off that monstrosity.
You live with the Framework, or you die with the Framework. In this case .. Are You Not Entertained?
Admin
I'm kind of curious to see the version history of this code. What would I find if I looked in trunk?
Admin
I think some people demonstrated a profound misunderstanding of templates vs generics. C++ (unmanaged) cannot have generics, definitely not the way they're done in .NET and probably not even the Java way. C# (the language, not .NET) and likely Java (again, the language, not JVM) could have supported templates, and they would, in some very narrow use cases, be slightly faster than generics; but generics provide many more benefits, and the performance improvements would be too insignificant and limited to too few use cases, to be justified. If you need to write something which is absolutely CPU-performance critical, you should use C++ or something similar, anyway; there is no way any managed language will ever match unmanaged performance. Also, some people said generics don't offer compile time type checking - what??!! Of course they do.
TLDR, this pissing contest of templates vs generics is meaningless. These are 2 different technologies, in 2 separate ecosystems, aimed at different goals.
Admin
Why would you need a managed environment for generics? The Java version of generics is just syntactic sugar that does not require anything new from the environment. I don't see why C++ could not do the same thing with pointers instead of handles.
You may want to think about that again. Managed environments know a lot more about the application than a compiler. Most projects do not use profile-guided optimization, but even if they did, a managed environment can profile the application in real-time and make better optimization decisions. GC can also be faster than manual memory management.
Admin
I've tried to find the root. But somewhere my company migrated from svn to git and the old repo is locked away somewhere. All the employees who designed this are all gone. The apps still using this have been running for over 5 years. Currently we're luckily getting money to migrate these old framework apps to .net 5/6, so we're just starting to rewrite them. A lot of work, but better in the long term.
Admin
So from this discussion we can conclude that Wargame's WOPR was written using C++ templates. No wonder it couldn't figure out how to beat the Russians at thermonuclear war.
Admin
Regarding performance of managed vs unmanaged I would say that a good enough developer would most likely always be able to beat the compiler and any runtime evaluation but as complexity grows it would be harder and harder to do and or most developers they just do not have the experience or deep understanding to beat the managed runtime, and any attempt would probably just add more bugs, extending development time so much that even that might spoil any gains while running the program ;)
Admin
Unmanaged languages including C++ cannot have generics because the value can be of various sizes. If you put all the values to a heap and the generic type holds pointers to those, 1) you're wasting performance on pointer resolution, 2) you're spending basically twice the amount of memory. But most importantly, you cannot get any of the benefits of generics; since we're unmanaged, there are no type descriptors, attributes, etc. So generics in C++ would be heavier than templates (a con) and not any better. People realized this and went with the template approach.
Addendum 2021-07-01 20:14: Re performance, in some cases managed frameworks can optimize some stuff away, but in a pedal to the metal scenario with heavy CPU workloads, there just isn't a way to optimize it away; unmanaged will be faster, period.
Admin
Yes, and the bad developer who cannot optimize a complex unmanaged codebase will also likely mess up a managed codebase in other ways. For example, managed frameworks are not immune to memory leaks.
Admin
Oh boy, I think Remy is for sure not a .net developer and tries to translate Java Hibernate knowledge to EntityFramework - which is a huge reason why I get always my believe confirmed that "Java developers are worse C# developer than people that never code before" :-)
Lets break it down, to clarify for all non .net developers how C# is layered.
Since the beginning of .net the frame had one major advantage over Java, with System.Data.Common database classes were introduced with abstract database access, no matter the database in the background. Sure, those were not perfect, clunky to handle and you still need to implement a lot database specific functionality especially when it comes to functionality that is way more advanced and goes beyond simple CRUDL operations.
So if you implement a Repository pattern, the correct starting point is System.Data.Common and perhaps use one of various mapper libraries to to the ORM.
EntityFramework is way beyond of a simple ORM mapper, it implemented the Unit Of Work pattern. People aware of this pattern know, that it implements the repository pattern, object mapping, versionized schema migrations plus state tracking in a context. This has the major advantage that you don't need to worry about transactions, because the context is the transaction over multiple repositories - one of the major shortcomings of a pure repository pattern implementation.
So the real WTF is that someone had the idea to implement a repository pattern over the unit of work pattern which implements the repository pattern for each database object. It's also very easy to spot in the given code: context.Set<T> is the repository pattern implementation.
Worse of all, directly changing the state of entities is never a good idea, for that you have methods like Add<T>, Update<T> and Remove<T> in the context. Those synchronize according to the Unit of Work pattern changes over all repositories and ensure that correct state for navigation objects as well.
Admin
The real WTF is that Microsoft used to recommend implementing a repository pattern over DbContext.
Admin
Another consideration: .NET does genetics differently than Java and it my understanding is correct, the performance aspect is closer to that of templates than generics in Java. Since the framework creates special types for generics, it can actually pass the values around without boxing them which i think Java cannot do - it always boxes because the underlying JVM type just deals with objects. So, instead of complaining that tempest are better than generics, one should complain that Java generics have their disadvantages.
Admin
psst...
...i heard you like programming, but you don't like doing programming to do your programming, so I made a language for you so that you can do your programming via templating (which is essentially programming your programming to do the programming) instead of programming.
Utopia achieved.
Admin
Thats gotta have been a pretty long minute. I made my first entity framewowrk implementation around 2012, and back then deriving from dbcontext was definately the only way to do an EF implementation.
Admin
Paulina, when i saw the code i thought we may actually be collegues XD This code seems copy/pasted from a project i'm currently working on!!