Simple scenario - how to

16 posts, 1 answers
  1. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 15 Dec 2009 Link to this post

    Dear All,

    Great Job - as usual by telerik, Developing the OpenAccess ORM.

    I have a simple database with three tables as follows:
    PHeader: {Code (PK:identity), requestID, description}
    IDdetails: {Code (FK), IDKey (identity), Source, Value}
    IDsubs: {Code (FK), IDKey (identity), Source, Value}

    PHeader : 1-n IDdetails
    PHeader : 1-n IDsubs

    I used the reverse mapping and I found the PHeader class has all the fields as the database, but the IDdetails & IDsubs doesn't have the CODE column, instead there is a reference to PHeader class;  Also I have noticed that the IDKey is created !! (shouldn't be as it is identity)

    Now, I am populating a user interface with data, and then I want to save the data into my database.

    I create a method for each peace of data named GetValue() that return the releated either IDdetails or IDsubs.
    From the main page I am doing the save as follows:

    PHeader ph = UserDetails.GetValues();  
    IDdetails[] ids = UserDetails.GetValues();  
    ScopeOfConsumer.Transaction.Begin();  
    ScopeOfConsumer.Add(ph);  
    for (int i = 0; i < ids.Length; i++)  
    {  
        ScopeOfConsumer.Add(ids[i]);  
    }  
    ScopeOfConsumer.Transaction.Commit(); 

     
    If what I am doing is correct;

     

    Now, I got the ph.Code value; how can I pass it to the IDdetails class, I try using the reference class in the IDdetail class but "Null reference" exception was thrown.

     

    What is the best approach for such case.

     

    Best regards

    Waleed

  2. TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 15 Dec 2009 Link to this post

    Hi Waleed,

    As far as I can see the reversemapping done by OA is correct.

    I don't know if the PHeader class has a List (any kind IList<IDetails>... whatever) and likely also an IList<IDsubs>?
    Nevertheless, the IDetails and the IDsubs classes "knows" who their "parent" is..namely an instance of the PHeader class.

    Let's assume that the above lists are in place on your PHeader class, all you have to do (within an object scope transaction) is:

    Assume you are only adding (creating new) instances:

    // Fill the header
    PHeader head = new PHeader();
    head.requestId = 1;
    head.description = "Test header";
    // Create a new List and add a member to it
    head.IDdetails = new List<IDdetails>();
    head.IDdetails.Add(new IDdetails());
    // Create a new List and add a member to it
    head.IDsubs = new List<IDsubs>();
    head,IDsubs.Add(new IDsubs());

    Hope this helps..

    Regards

    Henrik
  3. DevCraft banner
  4. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 15 Dec 2009 Link to this post

    Hello Henrik,

    Thanks for your reply.

    PHeader class doesn't have a list neither for IDdetails nor IDsubs.
    here is the IDdetails class:
    public partial class IDdetails  
    {  
        //The 'no-args' constructor required by OpenAccess.   
        public IDdetails()  
        {  
        }  
        [Telerik.OpenAccess.FieldAlias("iDKey")]  
        public long IDKey  
        {  
            get { return iDKey; }  
            set { this.iDKey = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("iDSource")]  
        public string IDSource  
        {  
            get { return iDSource; }  
            set { this.iDSource = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("iDValue")]  
        public string IDValue  
        {  
            get { return iDValue; }  
            set { this.iDValue = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("packetHeader")]  
        public PacketHeader PacketHeader  
        {  
            get { return packetHeader; }  
            set { this.packetHeader = value; }  
        }  
    and this is the PHeader:
    public partial class PHeader  
    {  
        //The 'no-args' constructor required by OpenAccess.   
        public PHeader()  
        {  
        }  
        [Telerik.OpenAccess.FieldAlias("code")]  
        public long Code  
        {  
            get { return code; }  
            set { this.code = value; }  
        }  
        [Telerik.OpenAccess.FieldAlias("bureauID")]  
        public string BureauID  
        {  
            get { return bureauID; }  
            set { this.bureauID = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("confidenceScore")]  
        public string ConfidenceScore  
        {  
            get { return confidenceScore; }  
            set { this.confidenceScore = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("description")]  
        public string Description  
        {  
            get { return description; }  
            set { this.description = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("requestID")]  
        public string RequestID  
        {  
            get { return requestID; }  
            set { this.requestID = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("responceCode")]  
        public string ResponceCode  
        {  
            get { return responceCode; }  
            set { this.responceCode = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("ticketID")]  
        public string TicketID  
        {  
            get { return ticketID; }  
            set { this.ticketID = value; }  
        }  

    how can I change it to be as you describ ..

    Regards
    Waleed
  5. TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 15 Dec 2009 Link to this post

    Hello Waleed,

    Create your changes in another partial class in another code file, say.. PHeaderExtensions.cs... doing so will not overwrite the changes you make if you reverse engineer your database later.

    Create the list a private field like:

    private IList<IDdetails> details = new List<IDdetails>();

    and then expose this private field as a public property (just like the other fields) in the original partial class in presumably PHeader.cs

    You do the same with the IDsubs class.

    When you are done doing your partial class extensions you must run the forward mapping (classes to table) and choose the new field "details" on the PHeader class.. In the Wizard you will have the option of choosing a reverse field for you 1:n relationship... you then choose the "packetHeader" field of the IDdetails class (which is essentially a reference back to the parent object - this PHeader class)

    Hope this clears things up:

    1. Do you extensions in a partial class (in a separate .cs file)
    2. Forward map and choose the "packetHeader" as reverse field in your 1:n mapping
    3. Go ahead an use the newly created List property of your PHeader class

    Regards

    Henrik
  6. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 15 Dec 2009 Link to this post

    Hello Henrik,

    I went through OpenAccess Reverse engineering process and I did the following:
    I expand the IDetails node under the tables node in the tree, and I select the pHeader field (this is automatically created by OC).
    on the right-side I check "Create one-to-many list", I did the same for Isubs.

    I press "Configure & Save" the created PHeader class is like this:
    public partial class PHeader  
    {  
        //The 'no-args' constructor required by OpenAccess.   
        public PHeader()  
        {  
        }  
        [Telerik.OpenAccess.FieldAlias("code")]  
        public long Code  
        {  
                get { return code; }  
            set { this.code = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("description")]  
        public string Description  
        {  
            get { return description; }  
            set { this.description = value; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("idetails")]  
        public IList<Idetails> Idetails  
        {  
            get { return idetails; }  
        }  
     
        [Telerik.OpenAccess.FieldAlias("isubs")]  
        public IList<Subs> Subs  
        {  
            get { return isubs; }  
        }  

    and the IDetails class still has the PHeader reference as follows:
    [Telerik.OpenAccess.FieldAlias("pHeader")]  
    public PHeader PHeader  
    {  
        get { return pHeader; }  
        set { this.pHeader = value; }  
    }  
     

    is this goes the same way you described ....or does it serve the approach.

    Best regards
    Waleed
  7. TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 15 Dec 2009 Link to this post

    Hi Waleed,

    Yep, it works either way, but doing as you did has the bonus that you do not have to maintain the extra extension .cs file for your partial class.
    If you feel your question was answered, please tick the Mark as answered.

    Regards

    Henrik
  8. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 15 Dec 2009 Link to this post

    Hello Henrik,

    I try to do this:

    PHeader

     

    ph = UserDetails.GetValues();

     

     

    ph.Idetails =

    new List<Idetails>();

    but the funcion at the PHeader class is missing the setter (this.idetails = value), why is it missing !!

    If I added the setter manually to the class (which is not quite easy if I have 30 class!!).
    Is it gona work as you described, I mean like: 
    for (i = 0; i < detailarray.length; i++)
    {
        ph.Idetails.Add(new Idetails());
        ph.Idetails[i].Source = ...........;
    }

    Best regards
    Waleed

     

     

     

     

     

  9. TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 15 Dec 2009 Link to this post

    Hi Waleed,

    You omitted the private fields declaration of your post of the classes (you only took the public properties).
    I think.. The reason why there's only a getter on the list is because the field is initialized like (in PHeader):

    private IList<IDdetails> details = new List<IDdetails>();

    With this initialization in place, you don't have to new the property... you can access the list (Details) directly like:

    header.Details.Add(....);

    Regards

    Henrik
  10. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 15 Dec 2009 Link to this post

    Hello Henrik,

    You are absolutely right !!

    I can call it like this : ph.Idetails.Add(new Idetail());

    Final question just to finish it up. I create a function getValues() to get back the Idetails from a datatable as follows
    Idetails[] id = new Idetails[idDataTable.Rows.Count] ;  
     
    for (int i = 0; i < idDataTable.Rows.Count; i++)  
    {  
        id[i] = new Idetails();  
        id[i].Source = (string)idDataTable.Rows[i][0];  
        id[i].Value = (string)idDataTable.Rows[i][1];  
    }  
    return id; 
    which returns an array of IDetails to the main saving function which is defined as follows:

    PHeader ph = UserDetails.GetValues();  
    Idetails[] ids = UserIdetails.GetValues();  
                  
    ScopeOfConsumer.Transaction.Begin();  
    ScopeOfConsumer.Add(ph);  
    for (int i = 0; i < ids.Length; i++)  
    {  
        ph.Idetails.Add(ids[i]);  
        ScopeOfConsumer.Add(ids[i]);  
    }  
    ScopeOfConsumer.Transaction.Commit();  
     
    How about the CODE field in the Idetails, I can't see how it will be assigned to a value of the parent CODE in the PHeader ?

    Can you explain that !!

    Best regards
    Waleed
  11. TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 15 Dec 2009 Link to this post

    Hi Waleed,

    Glad you made it work :-)

    Anyway, to your question, I am assuming you mean how the details will "know" of the parent, right?

    As this 1:m relationship is handled by OpenAccess it normally fills out the "reverse field". That happens when you do an Add on the list of details in the parent (your Header).

    Regards

    Henrik
  12. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 15 Dec 2009 Link to this post

    Hello Henrik,

    This what I thought ... Unfortunately it didn't ..

    I review the code of the save function as follows, can you please have a look at it
    protected void btnSave_Click(object sender, EventArgs e)  
    {  
        PHeader ph = UserDetails.GetValues();  
        Idetails[] ids = UserIdetails.GetValues();  
          
        ScopeOfConsumer.Transaction.Begin();  
        for (int i = 0; i < ids.Length; i++)  
        {  
            ph.Idetails.Add(ids[i]);  
        }  
        ScopeOfConsumer.Add(ph);  
        ScopeOfConsumer.Transaction.Commit(); 

    because I am getting an error says value code doesn't allow null in table idetails.
    What could be wrong !!

    Regards
    Waleed
  13. TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 16 Dec 2009 Link to this post

    Wait a second,

    Code is not the field (on the details class) that contains the reference back to the Header class... at least not from the latest source you posted....I think it is called the packetHeader field the one that references back to the Header class from the Details class
    So of course it is not set up by default

    There must be a null constraint on the field, so all you have to do is to fill this field

    Ehh, by the way... I can't see the Code field on the details class.. it is only on the Header class....or maybe I am a bit confused..

    Regards

    Henrik


  14. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 16 Dec 2009 Link to this post

    Hello Henrik,

    Let me explain this.
    I open telerik OpenAccess, then I reload the database once again, it create for the child table a reference to PacketHeader table upon the foreign key in the database. I click this reference and select "Create One-To_many" checkbox and I did this for both tables.

    The PacketHeader Class created is as follows:
    public partial class PacketHeader  
    {  
        private long code; // pk   
        private string description;  
        // inverse Identifier.pHeaderCode  
        private IList<Identifier> identifier = new List<Identifier>();    
        // inverse Surrogate.pHeaderCode  
        private IList<Surrogate> surrogate = new List<Surrogate>();    

    and the Identifiers class is as follows:
    public partial class Identifier  
    {  
        private long iDKey; // pk   
        private string iDSource;  
        private string iDValue;  
        // inverse PacketHeader.identifier  
        private PacketHeader pHeaderCode;   
    }  
     

    OpenAccess doesn't assign the code reference correctly UNLESS you assign the reference to the PacketHeader class created and assigned with values as follows:
    // Create and assign the header information  
    PacketHeader ph = UserDetails.GetValues();  
    // Create one child and assign values  
    Identifier tt = new Identifier();  
    tt.IDSource = "Source";  
    tt.IDValue = "100";  
    tt.PHeaderCode = ph;  
    // Add the child to the parent list           
    ph.Identifiers.Add(tt);  
     
    // Save all   
    ScopeOfConsumer.Transaction.Begin();  
    ScopeOfConsumer.Add(ph);  
    ScopeOfConsumer.Transaction.Commit();  
     

    and now it is working as expected !!.
    I guess the only missing part is that OpenAccess doesn't automatically assign the reference field with values unless you identify the reference to the PacketHeader Class (logical true).

    So if this is the correct approach I will continue like that and I think other getting started will benefit from this as well.

    Thanks and best regards
    Waleed
  15. Answer
    TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 17 Dec 2009 Link to this post

    Hi Waleed,

    So what you are saying is basically that you need to do the:

    tt.PHeaderCode = ph; 




    You can not only do the: ph.Identifiers.Add(tt)

    This might be the fact the the relationship is not "managed"... I don't remember if the option is there in the reverse mapping wizard - but in the forward mapping one you can choose to make the relationship between parent and child "managed"... This means that you can do either the tt.PHeaderCode = ph or the ph.Identifers.Add(tt) and OpenAccess, will "fulfill" the other side of the relationship.
    If the relationship is non-managed it is up to the developer

    Hope this shed some light one the issue.

    Regards

    Henrik
  16. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 17 Dec 2009 Link to this post

    Hello Henrik,

    Absolutely !!

    The OpenAccess doesn't manage the parent-child relationship in the reverse approach.
    If it could be implemented as the forward approach will be great feature to have.

    Thanks for your help
    Waleed
  17. TSE
    TSE avatar
    381 posts
    Member since:
    Sep 2008

    Posted 17 Dec 2009 Link to this post

    Hi Waleed,

    I think it is possible already in the reverse mapping mode:

    Before you run the wizard you should change the backend configuration.

    See in the docs for the "Managed one-to-many" section.. It defaults to false.. You should switch it to true and then reverse engineer..

    Oh, by the way.. The backend config is available from the OpenAccess menu.

    Try it out..

    Regards

    Henrik
Back to Top
DevCraft banner