Setting reference to another object

11 posts, 0 answers
  1. tmlipinski
    tmlipinski avatar
    131 posts
    Member since:
    Dec 2006

    Posted 26 Feb 2009 Link to this post

    Hi,

    A typical situation:
    • an "Order" table / class
    • a "Customer" table / class
    Both tables have integer, autoincremented IDs.
    "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

  2. Sharbel Lutfallah
    Sharbel Lutfallah avatar
    26 posts
    Member since:
    Feb 2006

    Posted 26 Feb 2009 Link to this post

    Hi Tomasz,

    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.
  3. DevCraft banner
  4. tmlipinski
    tmlipinski avatar
    131 posts
    Member since:
    Dec 2006

    Posted 10 Mar 2009 Link to this post

    Hi,
    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
  5. Dimitar Kapitanov
    Admin
    Dimitar Kapitanov avatar
    632 posts

    Posted 11 Mar 2009 Link to this post

    Hi tmlipinski,
    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.
  6. tmlipinski
    tmlipinski avatar
    131 posts
    Member since:
    Dec 2006

    Posted 11 Mar 2009 Link to this post

    Thanks.
    That is exactly what I've expected. And it's another thing that should be exactly written in the documentation.

    Regards
    Tomasz.
  7. Dimitar Kapitanov
    Admin
    Dimitar Kapitanov avatar
    632 posts

    Posted 12 Mar 2009 Link to this post

    Hello tmlipinski,
    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.
  8. tmlipinski
    tmlipinski avatar
    131 posts
    Member since:
    Dec 2006

    Posted 26 Apr 2009 Link to this post

    Hi,

    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

  9. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 27 Apr 2009 Link to this post

    Hi tmlipinski,
    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.
  10. tmlipinski
    tmlipinski avatar
    131 posts
    Member since:
    Dec 2006

    Posted 27 Apr 2009 Link to this post

    Hi,

    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
  11. Zoran
    Admin
    Zoran avatar
    534 posts

    Posted 16 May 2009 Link to this post

    Hello tmlipinski,

    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> 
    You should also add the following code in the set method of the Customer reference property. The reason for this is that currently, when you have a direct access to the foreign key, it's value is always the one going in the database.
    [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.
  12. tmlipinski
    tmlipinski avatar
    131 posts
    Member since:
    Dec 2006

    Posted 17 May 2009 Link to this post

    Hi,
    Thanks a lot for the detailed discussion of this issue.

    Regards
    Tomasz
Back to Top
DevCraft banner