A typical situation:
- an "Order" table / class
- a "Customer" table / class
"Order" has a reference to "Customer", of course. It's an integer column named, let's say, CustomerRef.
Now, I have a form for creating a new order. Among others, there is a combo on this form, for selecting a customer. Customers' IDs are the values of items' values. After entering all neccessary data, including selecting a customer, I press "Save". Then, I create a new "Order" object, fill its properties and, finally, I want to set the reference to the selected customer. In database's terms I should just put customer's ID (an integer) to the CustomerRef column (also integer). But CustomerRef property of the Order class is not an integer but Customer class. And this is an issue:
- I can, of course, use Database.OID.ParseObjectId and <objectscope>.GetObjectById methods to get the Customer object
- but will this algorithm ask the database for this object? or will it just create a nearly empty object filled with the ID only - wtihout asking the database?
If it is the first case - is there another option for setting the reference?
Regards
Tomasz
10 Answers, 1 is accepted
I too struggled with this at first, and my findiings were that your assumption is correct. Instead of doing:
order.customerID = 5;
You would do :
order.Customer = BLL_MethodToGetCustomer(5); (obviously a fictitious BLL method that returns the customer object by ID)
I tried to create a new customer object and set a reference to that in the order, but that will try to insert a new customer...
I believe your assumption is the way it should be done.
Thanks. From the functional point of view - it works. But what about efficiency? The key is - whether GetObjectById method asks the database for anything or (required behaviour) just creates an empty object filled with the ID only?
I think the authors of OA, i.e. somebody from the Telerik team should answer this question...
Regards
Tomasz
The behavior is like: when you request an object by an ID the L1 cache is checked whether there is a materialized object available. If so it is returned. However if the object is not available an empty object is created that has only the ID field initialized. Then after its properties are accessed, it is fetched from the database. Hope that helps.
Greetings,
Dimitar Kapitanov
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
That is exactly what I've expected. And it's another thing that should be exactly written in the documentation.
Regards
Tomasz.
Yes we will address this in the appropriate way.
Kind regards,
Dimitar Kapitanov
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
Your answer is that IObjectContext.GetObjectById works as follows:
- look for the object in the cache
- if found - return this object
- if not found - return a new, empty object with its ID initialized
I've done an experiment:
User u = scope.GetObjectById(Database.OID.ParseObjectId(typeof(User), pID.ToString())) as User;
(User is a persistent class, pID is variable containing the user's id)
When I set pID to some nonexistent value (123456) I received the message:
"No row for EX.Org.BLL.User ('User') GenericOID@1e244 User USR_id=123456 NOTRES "
Evidently OA searched the database.
And it is not bad: if I would ask scope for such a user just to work with it I would expect to receive this message at this moment, not later while accessing any property.
I think that you should add to IObjectContext a new method (GetObjectRef(IObjectId id)) that would explicitly return just a reference and would never access the database. If such a method would be added it would become clear:
- GetObjectById: look for a real, existing object (in the cache or in the database)
- GetObjectRef: create just a reference (maybe to a nonexisting object)
Regards
Tomasz
The functionality is designed in this way. We want to avoid situations where you get an error too late so that you can not find the real cause. This is why GetObjectById is directly checking the existance of the data.
What do you want to achieve? Why do you think a referenc to non existing data makes sense? You may have a constraint defined on the reference anyway and you will get the exception later in the commit call. And there is really no chance to handle it.
Sincerely yours,
Jan Blessenohl
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
My goal is described in the first post of this thread: I want to set the reference to an object of which I know its ID - but not the object itself. It is the ID of the existing object - so setting this reference makes sense. I have everything I need to set this reference from the SQL point of view: the ID of the object. But it is not enough from the ORM point of view: I still haven't got the object. And to get this object I must access the database - which is absolutely unneccessary.
This is the problem.
The solution is to be able to create a dummy (ghost, fake - call it as you want) object just with its ID set - and nothing else. And with no database access.
Regards
Tomasz
We have observed your scenario as well as some other similar cases and as a result, giving access to the foreign key fields directly is already part of our to-do list. A temporary workaround for our case is to manually write some code for the desired functionality and that is a field and a property accessing the CustomerID field as well as an app.config entry for the field.
The code should have the following form in the .cs files:
private int customerID; |
[FiledAlias("customerID")] |
public int CustomerID |
{ |
get{return this.customerID;} |
set{this.customerID = value;} |
} |
the app.config entry part of the Order class section should be as the following:
<field name="customerID"> |
<extension key="db-column"> |
<extension key="db-type" value="INTEGER" /> |
<extension key="db-column-name" value="CustomerRef" /> |
</extension> |
</field> |
[Telerik.OpenAccess.FieldAlias("customer")] |
public Customer Customer |
{ |
get { return customer; } |
set |
{ |
this.customer= value; |
customerID= customer.customerID; |
} |
} |
We are sorry for the delayed answer and once again I notice that this workaround is only temporary, in future the process will be much more automatized and manual code-behind or calling GetObjectById() will not be required in these circumstances.
Sincerely yours,
Zoran
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
Thanks a lot for the detailed discussion of this issue.
Regards
Tomasz