In your code data
is a list. So the reference to data.My_Object__r.Id
is not valid as My_Object__r.Id is an attribute of each element in the list, not the list itself. When you are querying for and the where clause is using Id = XXXX, you can typically just assign to a single instance of an sObject.
Also you are querying an value using a relationship where it is unnecessary. In a custom relationship, the following is always true.
object.Related_Object__c == object.Related_Object__r.Id
But the querying for the second is more expensive. So I would suggest the following:
public My_Main_Object__c data;
try {
data = [Select My_Object__c FROM My_Main_Object__c where id=:XXXX];
} catch (QueryException) {
data = new My_Main_Object__c();
//or handle the possible exception in some other way
}
if (data.My_Object__c != null){
returnedId = data.My_Object__c;
}
In all other cases, the best practice in Apex would be to assign to list, as you were doing iterate over the list to access the data:
data = [Select My_Object__r.Id FROM My_Main_Object__c where XXXX];
for (My_Main_Object__c mo : data){
returnedId = data.My_Object__c;
//or something else
}
Not treating a list as a list can be problematic.