Design questions

4 posts, 2 answers
  1. Smail
    Smail avatar
    10 posts
    Member since:
    Apr 2013

    Posted 10 Apr 2013 Link to this post

    Hello,

     We're migrating our solution to the Telerik OpenAccess ORM. We've got a couple of questions about how the ORM could fit into our current system design. Specifically we're using a 3-layer design  (Domain Driven Design), each of our modules has 3 main folders where each layer is located into.

    + Presentation
    + Domain
    + Enums
    + Models
    + Data

    So in the Data layer we have static classes that represent our repositories, within each repository we have methods for the basic CRUD operations. What we want to achieve is replace the implementation of the CRUD methods with calls to the ORM Open Access Context.

    Here comes our main problem, in the ORM every CRUD operation is done via the OpenAccess Context, however there are three ways in which we can implement that. The problem is mainly with long-lived entities that have to be passed from one WinForm to another (or generally used by some business logic class).

    In the below code snippet we've outlined the three ways we can implement the CRUD operations with the ORM.

    V1 - the main problem is we're not leaving a reference to the context, what would happen if the GC runs and disposes the context?
    V2 - creating a detached copy, this works but we're basically not using the ORM to its full potential and add more code to create detached entities.
    V3 - having a global OpenAccess Context that we keep, what happens when you query it multiple times for the same objects (refreshing a list of items for example). With this our main concern is it may eat up resources while trying to keep track of multiple objects that will never get commited to the DB.

    public static class PatientRepository
        {
            //Variant 1
            public static Patient F_GetPatientByID_V1(uint patientID)
            {
                return new EntitiesModel().Patients.Where(p => p.PatientID == patientID).FirstOrDefault();
            }
     
            //Variant 2
            public static Patient F_GetPatientByID_V2(uint patientID)
            {
                using (var dbContext = new EntitiesModel())
                {
                    Patient pat = dbContext.Patients.Where(p => p.PatientID == patientID).FirstOrDefault();
                    return dbContext.CreateDetachedCopy<Patient>(pat);
                }
            }
     
            //Variant 3
            private static EntitiesModel DbContext = new EntitiesModel();
            public static Patient F_GetPatientByID_V3(uint patientID)
            {
                return DbContext.Patients.Where(p => p.PatientID == patientID).FirstOrDefault();
            }
     
        }
  2. Answer
    Viktor Zhivkov
    Admin
    Viktor Zhivkov avatar
    291 posts

    Posted 11 Apr 2013 Link to this post

    Hi Smail,

    If you want to keep your code similar to the one that you have been using (having plain classes that represent the business objects and loading/persisting them with static classes that act as repositories) the best way will be to use short living context and detach entity instances (or even graphs of objects) after they have been loaded; and attach an entity (or graph) to the context before it is saved. This should allow you to hide the presence of the ORM behind your repository classes.

    Here are my comments on the different variants that you have in ming:
    • Variant 1: this is not a good idea. The context instance is "too short-living" and as you noted will be release too soon. OpenAccess entities require to have a living context in order to be able to manipulate them unless you detach them. After the detach they can live on their own.
    • Variant 2: this is the variant that I would go for. There you can define which related objects are to be loaded with the current entity (like loading all history records for the current patient) so after you method returns you already have a lot of information to work with. Detaching the entity will enable you to free any resources used by the context. This approach will enable you also to handle easily any parent-child scenarios where a parent object is created and the user is able to add to it several related child objects in the same transaction. Imagine scenario like this:
      1. User wants to register a new patient - opens Register Patient dialog;
      2. User fills in all information about the new patient;
      3. User wants to attach several entries in the Historical Records of the patient - opens a new sub-dialog;
      4. * Historical Records should not be saved before the patient is. To improve the workflow the patient and the historical records should be saved when the patient is saved;
      5. User finishes adding historical records - closes the sub dialog and returns to Register Parient dialog;
      6. User saves the patient and his historical records by pressing save on the Register Parient dialog.
      What are your concerns that 
    "...we're basically not using the ORM to its full potential and add more code to create detached entities"?

    You can find more information about Attach-Detach API here.
    Also another useful bit of information will be this article about our Fetch Strategies that can come handy when detaching object graphs.
    • Variant 3: In general there will be only one copy of an entity in the context's memory, but during the lifetime of the context it can gather a lot of data which can cause the memory consumption to go up. Another problem can be the fact that context.SaveChanges() will commit ALL changes made to the context when it is called so you have to make sure that there is only one transaction that is active at a time.
    If you need any further assistance getting started with OpenAccess, do not hesitate to contact us again.

    Regards,
    Viktor Zhivkov
    the Telerik team
    Using Encrypted Connection Strings with Telerik OpenAccess ORM. Read our latest blog article >>
  3. DevCraft banner
  4. Smail
    Smail avatar
    10 posts
    Member since:
    Apr 2013

    Posted 11 Apr 2013 Link to this post

    Hi Viktor,

    Thank you very much for your prompt and comprehensive reply.
    I realise that in my case (where all my repositories are implemented as static classes), the best suited approach is the second variant.

    It's not problem for me to make all my repositories non-static classes, if it is worth the change. I don't know whether it's worth at all.

    At present my main consern is to find working pattern(s) that would allow me to optimally use the Telerik Open Access ORM in the context of Design Driven Domain model  in  winforms(wpf) desktop applications.

    I have already got familiar with the provided samples (from OpenAccess Samples Kit) but I could not find any working solution (patterns) in the above mention context.

    I would appreciate your assistance in finding such working patterns.

    Thank you in advance for your assistance.

  5. Answer
    Viktor Zhivkov
    Admin
    Viktor Zhivkov avatar
    291 posts

    Posted 11 Apr 2013 Link to this post

    Hi Smail,

    You can keep your repositories static. The important thing there will be to create a new instance of you context in each method. If you see that some methods are usually called in chain and can reuse the context instance, then you can move to non-static repositories that create the context in their constructor and are disposed after the data is loaded in memory or persisted in the database.

    I am afraid that we do not have any examples that demonstrate how to use Domain Driven Design and OpenAccess. I believe the best way to see how things fit together is either by using OpenAccess for a single form/dialog in your existing code or by setting up the same environment in init or integration tests.

    Moving from manually implemented data layer to ORM-based requires to overcome a certain learning curve and change a bit your mindset how to handle data. The best way to overcome these obstacles is to start building simple components and gradually move to more complex scenarios. If you face any difficulties during that process, you can always send your questions to us.

    Kind regards,
    Viktor Zhivkov
    the Telerik team
    Using Encrypted Connection Strings with Telerik OpenAccess ORM. Read our latest blog article >>
Back to Top