If I'm understanding you correctly, you have an object with a lookup field that you always want to associate to the same record. If that is the case, then there must be something distinguishing that record, for example its name. In that case, you would build a query and then reference the returned Id.
Object1__c o1 = [SELECT Id FROM Object1__c WHERE Name = :'DEF' LIMIT 1];
Object2__c o2 = new Object2__c();
o2.Object1__c = o1.Id;
It is true that hard-coding an Id is bad practice. Let's look at why. Here are a few scenarios:
- If you are planning on migrating this to another environment (sandbox to sandbox or production) then the ID of your record will change. What will work in SandboxA won't work in SandboxB because even if you create the exact same record, the ID will be different.
- If you delete that record, you have to go fix all of your hard-coded Ids. That is difficult to manage.
- Say that someone deletes your record. Obviously that would result in a few errors in your code. Hopefully what you would do with your query is then check to make sure there is a record that is being returned, and if not, you can handle the error properly.
- It makes your code less understandable. No one has any idea what 'aBbb0000000PBvNCAW' refers to until they go look up that record (which may be difficult if you made the record in one environment and they are in another.) With a query, another developer (or future you) will be able to understand that you are getting a record with the name 'DEF'.