N-Tier Windows Forms

Posts   
 
    
stodge
User
Posts: 2
Joined: 18-Oct-2007
# Posted on: 18-Oct-2007 10:06:19   

Is there available and end-to-end example of a Winforms client that uses LLBLGen over a Web Service? I've seen many threads that touch on this, but none that show code examples for each tier.

In my previous system we filled typed datasets from the database and sent these across the wire using Web methods. DataGridViews were bound to these, and on hitting save we did a GetChanges, sent this up to the server, did a save, sent this back down to the client and Merged this back into the dataset the grid was bound to. During the save our Oracle stored proc updated columns such as ModifiedTime (used for optimistic locking), ModifiedUser etc which was automatically updated in the DataRow and merged back into the DataSet on the client. The new values appeared in the grid.

This all worked very well but it was time consuming to develop, which is where I was hoping LLBLGen would speed up our development. However I have not yet successfully proved this and currently am getting a load of ORMEntityOutOfSyncException exceptions on the client.

My server WebMethod is as follows:

       [WebMethod]
        public EntityCollection<StodgepartyEntity> Save(EntityCollection<StodgepartyEntity> deletedEntities, List<StodgepartyEntity> dirtyEntities)
        {
            EntityCollection<StodgepartyEntity> dirtyCol = new EntityCollection<StodgepartyEntity>();
            dirtyCol.AddRange(dirtyEntities);
            using (DataAccessAdapter adapter = new DataAccessAdapter())
            {
                UnitOfWork2 uow=new UnitOfWork2();
                uow.AddCollectionForDelete(deletedEntities);
                uow.AddCollectionForSave(dirtyCol);
                uow.Commit(adapter);
            }
            return dirtyCol;
        }

The client Save method is:

      private void buttonSave_Click(object sender, EventArgs e)
        {
            FxPosManServiceClient.WebService.StodgeLLBLGenWebService ws = new StodgeLLBLGenWebService();
            ws.Credentials = CredentialCache.DefaultCredentials;

            EntityCollection<StodgepartyEntity> res = ws.Save(_deleted,_dataSource.DirtyEntities);

            Context context = new Context(true);
            context.Add(_dataSource);
            foreach (StodgepartyEntity returned in res)
            {
                StodgepartyEntity fetched = (StodgepartyEntity)context.Get(returned);
                fetched.Fields.State = EntityState.Fetched;
                 fetched.IsDirty = false;
                context.Get(returned);
            }
            dataGridView1.Refresh();
            MessageBox.Show("Saved");
        }

For optimistic locking we are using the following:

   [DependencyInjectionInfo(typeof(IEntity2), "ConcurrencyPredicateFactoryToUse",
        ContextType = DependencyInjectionContextType.NewInstancePerTarget,
       TargetNamespaceFilter = "InHouse.FXPosMan.LLBLGen")]
    [Serializable]
    public class GeneralConcurrencyPredicateFactory : IConcurrencyPredicateFactory
    {
        public IPredicateExpression CreatePredicate(ConcurrencyPredicateType predicateTypeToCreate,
            object containingEntity)
        {
            IPredicateExpression toReturn = new PredicateExpression();
            EntityBase2 entity = (EntityBase2)containingEntity;


            IEntityField2 field = entity.Fields["ModifiedTime"];
            EntityField2 f = (EntityField2)EntityFieldFactory.Create(entity.GetType().Name, "ModifiedTime");

            switch (predicateTypeToCreate)
            {
                case ConcurrencyPredicateType.Delete:
                    toReturn.Add(f == field.CurrentValue);
                    break;
                case ConcurrencyPredicateType.Save:
                    // only for updates
                    toReturn.Add(f == field.CurrentValue);
                    break;
            }
            return toReturn;

        }
    }

which seems to work (an Oracle trigger updates ModifiedTime).

I've seen a thread that suggests reselecting all the rows and rebinding on the client, but this is wasteful if say only 100 out of 1000 rows have been updated, and is awkward for maintaining the users editing position in the grid.

Thanks in anticipation.

Stodge.

Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 18-Oct-2007 12:11:15   

I was hoping LLBLGen would speed up our development. However I have not yet successfully proved this and currently am getting a load of ORMEntityOutOfSyncException exceptions on the client.

It would be helpful if you post a stack trace of one of those exceptions, and the LLBLGen Pro runtime library version. With the corresponding code snippet.

Anyway try this: At the server, use the following overload of the UOW.AddCollectionForSave(), to refetch the saved entities. To avoid the OutOfSync exception.

public virtual void AddCollectionForSave( 
   IEntityCollection2 collectionToSave,
   bool refetch,
   bool recurse
)

Pass true for refetch.

stodge
User
Posts: 2
Joined: 18-Oct-2007
# Posted on: 18-Oct-2007 12:47:33   

Thanks for your response. Changing the server code to

uow.AddCollectionForSave(dirtyCol,true,false);

has fixed the exception. However in the client I am not always getting the returned values merged into the datasource. They are for the first call but not for the second.