Problems/Questions on working with WinForms

Thread is closed for posting
7 posts, 0 answers
  1. Schmidty
    Schmidty avatar
    22 posts
    Member since:
    Jan 2007

    Posted 12 Mar 2010 Link to this post

    I've had great luck with OpenAccess in a web environment & I am having some issues doing it in a WinForms environment. I am using the ScopeFactory method to get my IObjectScope from the thread. My object scope is managed from a static class:

        public class ScopeContextManager 
        { 
            private static IObjectScope _scope; 
     
            static ScopeContextManager() 
            { 
            } 
     
            /// <summary> 
            /// The current scope. 
            /// </summary> 
            private static IObjectScope CurrentScope 
            { 
                get 
                { 
                    if (_scope == null || !_scope.Transaction.IsActive) 
                    { 
                        _scope = GetCurrentScope(); 
                    } 
                    return _scope; 
                } 
            } 
     
            /// <summary> 
            /// Returns the current scope for the application. 
            /// </summary> 
            /// <returns><c>IObjectScope</c> object.</returns> 
            public static IObjectScope GetCurrentScope() 
            { 
                return GetScopePerThread(); 
            } 
     
            /// <summary> 
            /// Begins the transaction for the current scope if the transaction is not active. 
            /// </summary> 
            public static void BeginTransaction() 
            { 
                if (!CurrentScope.Transaction.IsActive) 
                { 
                    CurrentScope.Transaction.Begin(); 
                } 
            } 
     
            /// <summary> 
            /// Commits the transaction for the current scope if transaction is still active. 
            /// </summary> 
            public static void CommitTransaction() 
            { 
                if (CurrentScope.Transaction.IsActive) 
                { 
                    CurrentScope.Transaction.Commit(); 
                } 
            } 
     
            /// <summary> 
            /// Rolls back the transaction for the current scope if transaction is active. 
            /// </summary> 
            public static void RollbackTransaction() 
            { 
                if (CurrentScope.Transaction.IsActive) 
                { 
                    CurrentScope.Transaction.Rollback(); 
                } 
            } 
     
            /// <summary> 
            /// Gets the object scope for the thread. 
            /// </summary> 
            /// <returns></returns
            private static IObjectScope GetScopePerThread() 
            { 
                IObjectScope scope = null
                string key = Thread.CurrentContext.ContextID.ToString(); 
                LocalDataStoreSlot slot = Thread.GetNamedDataSlot(key); 
                if (slot != null) 
                { 
                    scope = (IObjectScope)Thread.GetData(slot); 
                } 
                if (scope == null) 
                { 
                    scope = ObjectScopeProvider.GetNewObjectScope(); 
                    if (slot == null) { 
                        slot = Thread.AllocateNamedDataSlot(key); 
                    } 
                    Thread.SetData(slot, scope); 
                } 
                return scope; 
            }      
        } 

    I am using SQL Server CE as my database, and am having an issue getting the data saved. I might be just overlooking this problem and thought I'd post this to see if someone can help me.

    I have a form with a button that opens a form to create a new quarter. From this quarter form, here is my code to add a new quarter:

     if (String.IsNullOrEmpty(txtQuarterName.Text)) 
                { 
                    MessageBox.Show("Quarter name is required."); 
                    return; 
                } 
     
                try { 
                    ScopeContextManager.BeginTransaction(); 
                    Quarter quarter = new Quarter(); 
                    quarter.Name = txtQuarterName.Text; 
                    quarter.StartDate = dtpQuarterStartDate.Value; 
                    quarter.EndDate = dtpQuarterEndDate.Value; 
                    quarter.Description = txtQuarterDescription.Text; 
                    QuarterService quarterService = new QuarterService(); 
                    quarterService.Save(quarter); 
                    ScopeContextManager.CommitTransaction(); 
                    this.Close(); 
                } 
                catch(Exception x) { 
                    ScopeContextManager.RollbackTransaction(); 
                    MessageBox.Show(x.Message); 
                } 
     

    The Save function on Quarter Service adds the object to the object scope. Now when the form closes & returns to the parent form, I refresh a grid of "Quarters" where my recently created Quarter shows up. It appears it's saved in the DB, but when I close the application & view the DB it is empty. It seems to me that it should be added.

    I don't know if my approach is way off as the ScopeFactory example doesn't show how to work with transactions (opening/committing) & I don't know what the practice is to handle these transactions for a WinForms app.

    If anyone has any suggestions or sees something wrong with my approach, any help is greatly appreciated. As I said, I'm gotten OA to work great in my web application but this my first WinForms attempt with OA.

    Thanks,

    Mark
  2. Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 15 Mar 2010 Link to this post

    Hello Schmidty,

    Thank you for the detailed explanation. Unfortunately we were not able to reproduce the failing behavior. I have attached my testing project, maybe you will be able to see the differences between this and your project and that could lead us to the problem. Please let us know if you get some results.

    Best wishes,
    Damyan Bogoev
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  3. Schmidty
    Schmidty avatar
    22 posts
    Member since:
    Jan 2007

    Posted 16 Mar 2010 Link to this post

    Hi Damyan,

    I'm glad to let you know that during the process of comparing your project to mine I found what my "issue" was. I had my .sdf in a data folder in my App project, and when I debugged I saw that it was using a sdf created in the debug folder. I didn't know this, and would explain why I didn't see any updates in my "original" DB in my app project. Thank you for compiling the project.

    One more thing...am I handling the object scope properly based on my "scope factory" class? As I said, I haven't used OA in a Winforms app before & just want to make sure I am doing it correctly.

    Thanks!

    Mark

  4. Sergej Mertens
    Sergej Mertens avatar
    34 posts
    Member since:
    May 2009

    Posted 16 Mar 2010 Link to this post

    Hi Schmidty,

    whether you handle object scope right or not depends on your needs. Telerik recommends using it in your way. For me in a mid-size app this approach doesn't satisfied me. In WinForms-Apps it is common to have rich data binding. Let's say we have a list of customers. Now you double-click a customer and an edit window with data binding to one object appears. If you edit data in this window, while the list gets updated in the background while you were typing. Moreover, if you open a second edit window with another customer and want to save only one, this is not possible with thread-based scopes. All objects share the same scope and by commiting the transaction for the "first" item, you also commit changes done on the "second" item. In this easy scenario it could be handled different (wrapping editing in a ViewModel-like approach, avoiding direct binding). But I also have more complicated business logic that works on one object and all of it's dependencies (like invoice with items, customer, distributor, etc.): with this in mind I create a scope for every "business case", which I can track in transactions without affecting other data. I simply created business services which indeed request a scope from my scope factory (a kind of GetNewObjectScope()).

    Greetings,
    Daniel
  5. Sörnt Poppe
    Sörnt Poppe avatar
    46 posts
    Member since:
    Mar 2010

    Posted 16 Mar 2010 Link to this post

    "Scope per business case" that sounds interesting.

    I guess you have some standard dialogs which are invoke from different places. Do you pass your "bussines case" to thoses standard dialogs in order to fetch/edit/delete releated objects within the same scope?
  6. Sergej Mertens
    Sergej Mertens avatar
    34 posts
    Member since:
    May 2009

    Posted 16 Mar 2010 Link to this post

    Hi Schmidty,

    yes, thats exactly the way I use it in a CAB/SCSF-based app. As I treat WorkItems as business case, there is a factory-service for a special business case in my DAL-Module which gets a scope depending on the WorkItem I put in as parameter. Therefore there are several views which represent "standard dialogs" like "EditCustomerView" which mustn't be present in the same module - a service call passing the businessa case object (wich includes the scope) does the rest.

    Greetings,
    Daniel
  7. Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 17 Mar 2010 Link to this post

    Hello Schmidty,

    You should slightly modify the GetScopePerThread method in the following way:
    if (slot != null)
    {
        scope = Thread.GetData(slot) as IObjectScope;
    }

    This change is required because in case when the value stored in the slot is not of type IObjectScope the method will throw a casting exception.
    The rest of the pattern you use for handling the IObjectScope in your application is correct.

    Greetings,
    Damyan Bogoev
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
Back to Top