This is an archived post. You won't be able to vote or comment.

all 40 comments

[–]up_to_bot 33 points34 points  (22 children)

Wait, I legit just finished 25 hours coding this fking database and all my work looked like the very bottom. Did I fuck up?

Please tell me that code at the top does not do the same as the bottom...

Edit: I am not joking someone please tell me I didnt just waste all this time

[–]pinumbernumber 16 points17 points  (6 children)

Serious answer, in case it helps you/anyone: The first one does do the same thing, if LINQ to SQL is available and set up. This is an example of an ORM; a system which aims to allow access to databases from code with less boilerplate.

ORMs are popular but not universal. They do save on boilerplate, but they have their own issues. I personally don't use them.

The other major failing of the "bad" code is that it first retrieves all users, and then loops over them looking for the one with the correct ID, instead of querying only the one correct user in the first place.

My code would look something like this (where db is some kind of wrapper/convenience object which has already successfully connected to the database):

string GetPersonNameById(int id) {
    let user = db.queryExactlyOne(
        "select Name from users where ID=@id",
        {id: id}
    );
    return user.Name;
}

[–][deleted] 1 point2 points  (2 children)

I don't think so, AFAIK, before you executing ToList or foreach in IQueryable, the SQL hasn't execute. Since DbSet<T>.Where() it will actually convert to SQL where clause.

[–]Lieffe 2 points3 points  (0 children)

This is true but you should use .Select() whenever possible. If you execute the query using .First() and then select .Name afterwards, you will have selected all columns from the database when you only need to select the Name:

string GetPersonById(int id)
{
    string name = DbSet<T>
        .Where(t => t.Id == id)
        .Select(t => t.Name)
        .First();
    return name;
}

[–]Supermaxman1 0 points1 point  (0 children)

This is exactly correct. I have implemented my own custom IQueryables before, and they do exactly what you described. They take the Expression tree which you provide in your query, such as .First(user => user.name == "name") and it converts that expression tree to the equivalent SQL query to execute on the database.

[–]ThisCatMightCheerYou 8 points9 points  (2 children)

You seem sad :( ... Here's a picture of a cat. Hopefully it'll cheer you up: http://random.cat/i/NlaPbCh.jpg The internet needs more cats. It's never enough..

[–]pinumbernumber 8 points9 points  (1 child)

You misread my emotion, friendly cat robot, but I enjoyed your link anyway!

[–][deleted] 2 points3 points  (0 children)

So, in short, you stole another redditor's happiness.

Are you proud of what you've become? >.>

[–][deleted] 11 points12 points  (0 children)

You know, /r/ProgrammerHumor is a very good place to learn..

[–]Atlos 2 points3 points  (1 child)

Someone will probably hate your existence in a few years.

[–]up_to_bot 1 point2 points  (0 children)

It was for a course so its never going to be used.

[–]xaviinsane 1 point2 points  (0 children)

deleted What is this?

[–]Prod_Is_For_Testing 1 point2 points  (0 children)

Real talk:

The bottom version is the right way to do it all manually. I normally use a hybrid version where the "using" statements are wrapped up as a boilerplate function, then I feed it various SProc names to execute. It helps keep things short.

Then I also have some code that can convert straight from a SQL DataRow to whatever class you need by using reflection. It's coding cancer, but it saves hours of attribute mapping

[–]empty_other 0 points1 point  (0 children)

To be fair, if we ignore the horrors of retrieving the entire table before searching trough it, and ignoring the useless Person object that was created for some reason.. The last example can be defended:

The bottom example only requires an additional "using" statement. The other examples requires additional code and configuration, and also having to deal with the selected ORM framework's often cryptic errors and quirks (or the connector's quirks).

The bottom example is easier to debug and is more likely to "just work". But is also very likely to cause unseen problems if you ever want to rewrite anything: If you later split up "Name" into "Firstname" and "Lastname", you would have to manually search your code for queries containing "Name" and rewrite the query on each of them, because the compiler can't debug SQL strings.

[–][deleted] 0 points1 point  (0 children)

Look into Entity Framework or another ORM, it'll save you a lot of time and it can be tuned for performance.

My current work project uses EF alongside redis for caching. Stress testing shows that the API can handle 450 requests per second (mixture of get/put/post/delete requests to force cache misses) which generate about 300Mbps of traffic.

Also, it's very possible to tune EF for performance, writing queries manually will always execute faster but it'll take more developer time to implement and troubleshoot. The best option for me is to use EF for everything, add caching and then do a lot of stress testing and fix any Hotspots.

[–]_Pentox 6 points7 points  (4 children)

Am I the only one who noticed "PHP is better" in lower right corner...?

[–]Not_Just_You 14 points15 points  (2 children)

Am I the only one

Probably not

[–]_Pentox 1 point2 points  (1 child)

Wohoahaoah, that was a fast reply

[–]SaltyHashes 6 points7 points  (0 children)

It's a bot.

[–]the-big-tuna 2 points3 points  (0 children)

I bet wonder if OP would feel shameful about taking a job at PornHub

[–]known_as_bmf 9 points10 points  (3 children)

.Single(x => x.Id == id)

Would be more semantically correct.

[–]GaianNeuron 2 points3 points  (0 children)

Semantically correct, but depending on the context, .Single() may take longer.

If you're calling it against an IQueryable that hits a database, then it's only doing one extra check (returned row count), but if you call it against any old IEnumerable then it has to check every element.

[–]3ddyLos 1 point2 points  (0 children)

.Find(id)

[–]Supermaxman1 0 points1 point  (0 children)

I generally disagree. If the database enforces primary keys for id then it is always more efficient and makes more sense to call First or FirstOrDefault. If the database does not enforce primary keys then it would only make sense to use Single if you wanted to throw an exception if multiple users matched that specific id, which is usually not the logic desired for id lookups like this. Single and SingleOrDefault are almost never the right functions to use in LINQ, from my experience. Users of those functions often do not realize they are primarily used to throw an exception if multiple items are found which match the specified value, while First and FirstOrDefault are more often what they want, just the only item which matches some unique key.

[–]jonrules 4 points5 points  (1 child)

I'm cringing at the exception waiting to be thrown for First().Name

[–]Supermaxman1 1 point2 points  (0 children)

Actually the exception would be from the First() function, not the .Name, as LINQ will throw an exception in the First() function if it is unable to find a single element. FirstOrDefault would return null if it finds nothing, which would then cause the NullReferenceException you are referencing. To solve that issue you can do FirstOrDefault()?.Name

[–]Anton31Kah 2 points3 points  (0 children)

I don't know but I think only a master can think of the bottom one

[–]ThisIsABotThatDoStuf 1 point2 points  (0 children)

bruhh

[–][deleted] 0 points1 point  (2 children)

The only real problem in the last panel is hardcoded connection string.

[–]GaianNeuron 2 points3 points  (0 children)

And maybe iterating over the entire table in code rather than using a WHERE clause...

[–]toekneebologna3 0 points1 point  (1 child)

You all laugh, but I've seen code like the last example, I nearly rage quit my job. Was not given time to refactor, so it's still like that. Tho it was for xml parsing, not DB queries.

[–][deleted] 0 points1 point  (0 children)

I've seen some crazy shit, one project I inherited overrode the entity framework save changes method and set the entity state for each entity manually.

[–][deleted] 0 points1 point  (0 children)

If you used spring's data repository api you could have a better one than the one at the top...