I've recently come across an EF6 application where the logic is driven heavily by the use of IDs, something I hadn't seen before.

Once an entity is loaded by EF at the DAL, it is mapped to another near-identical POCO object which sits in the Business Logic layer.

Whenever entities are worked with in the Business Logic, the relationships are determined using IDs, for example:

var applesOnTree = forestApples.Where(a => a.TreeID == tree.ID)

This seemed extremely odd to me, whereas before I'd always worked with applications which expressed relationships using objects:

var applesOnTree = tree.Apples;

Is it normal to use generated IDs in the Business Logic like that when using EF?

It feels strange personally. Is it a better practice to never work with IDs except in the DAL layer? Or is this ability considered a useful benefit of EF?

I suppose it's useful in that it allows you to track what has/hasn't been persisted to the DB yet?

  • This solely depends on the context you are working in. Notice that in the first example you have a forest of apples and you are only interested in the apples of a particular tree. In the second example you already have that particular tree along with its apples, but the logic to find its apples still had to be somewhere else. – Andy Jul 27 '17 at 12:58
  • This is true. To rephrase, should you ever find yourself needing the first example? Would it not make more sense to always let EF build all these relationships into objects when they're pulled from the database? I can't see a benefit of using the first approach - I'm wondering if there is one which I've missed (to explain why the entire app is written this way). – FBryant87 Jul 27 '17 at 13:07
  • I don't see why not. There may be a case for that. – Andy Jul 27 '17 at 13:10
  • In a database where your sole means of retrieving a single, unique record is a synthetic ID, working with such ID's is quite common. I'm a bit surprised you've never seen it before. Note that the two code examples you've provided in your question are not equivalent. – Robert Harvey Jul 27 '17 at 18:02

This seems like standard practice to me. The only thing that's unclear is why you relate it to EF?

The problem with Tree.Apples is that:

  • Its inefficient to retrieve apples tree by tree rather than GetTreesInForest(3), GetApplesInForest(3) and then map them up.

  • You find each Apple has Seeds which also need to be populated. Now you cant get a single tree without bringing back a tonne of data. You are forced to have TreeLites or lazy loading, all of which is more complicated than simply not having child objects.

  • Interesting point. The thing is the code gets substantially more bulky this way - every time you need to get related objects, you need to write a LINQ statement to find what you need. Additionally you're often doing more work this way if the work is done frequently (cheaper to just load it all in to Tree.Apples at the start). I suppose it depends heavily on the domain and how much data you're working with. – FBryant87 Jul 28 '17 at 9:35
  • no, you have exactly the same code if you think about it. you've just moved the mapping out of the DAL and into the Business Layer so you can use it optionally instead of all the time. – Ewan Jul 28 '17 at 10:15
  • But the functions in the Business Layer are having to do that work again and again everytime they're called. The mapping in the DAL is only performed once. – FBryant87 Jul 28 '17 at 12:50
  • There's nothing forcing you do that, You can pass around or persist the mapping if you like. But most of the time it will be more efficient not to. If your app has Tree.Apples, loads the 5 trees in your garden when the app starts and keeps them in memory until it exits, fine. But if you have an Orchard with 1000's of trees each with 100's of apples you don't want to load and map all the data just to pick one apple. – Ewan Jul 28 '17 at 13:09
  • Agreed, comes down to the last line of my first comment. – FBryant87 Jul 28 '17 at 13:27

Relational models and object models are not the same.

You don't have to model with objects because your data is in memory. You don't have to use a relational model because your data is in a database.

However, traditionally, that's how it's been done. Why it's been done that way has more to do with the tools then with design. Trying to work with both models creates the Object-relational_impedance_mismatch.

And of course there are tools to fix these tool created problems: Object-relational_mapping

This isn't to say you should only ever work with one model. But when you work with two you're creating real work. Delegate that work to a tool and don't be surprised if it lets you down. I know shops with teams of people dedicated to taking this work back from the tool.

  • 1
    Sure. But what about the use of bare ID's (what the OP is asking about)? – Robert Harvey Jul 27 '17 at 17:59
  • @RobertHarvey in a pure object model the reference is the ID. For value objects (like string) it's a hash on the values. For entities it's an ID that was uniquely and finally set when it was born. The difference between references and ID's is the context within which they are unique. – candied_orange Jul 27 '17 at 19:32
  • In any relational database system design (which includes the DTOs to which the database tuples map) that uses synthetic keys, the ID is the one you describe for entities. Any such system worth its salt uses globally-unique IDs. – Robert Harvey Jul 27 '17 at 19:38
  • @RobertHarvey GUIDs can be nice but are not universally used. If you can point me to a job where every system I will touch will be worth it's salt please do : ) – candied_orange Jul 27 '17 at 20:12
  • ...for some definition of "globally." (it doesn't necessarily have to be a GUID, nor does it have to be unique beyond that particular system). – Robert Harvey Jul 27 '17 at 20:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.