Print Page | Close Window

Where can I find document for how to implement the GenerateID() interface?

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2009
Forum Discription: For .NET 3.5
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=1436
Printed Date: 05-Jun-2024 at 11:28am


Topic: Where can I find document for how to implement the GenerateID() interface?
Posted By: Suah
Subject: Where can I find document for how to implement the GenerateID() interface?
Date Posted: 20-Aug-2009 at 9:52pm
Where can I find document for how to implement the GenerateID() interface?



Replies:
Posted By: GregD
Date Posted: 24-Aug-2009 at 4:13pm
There are a couple of mentions of IIDGenerator in the Developer Guide, which describe at a high level what it does. Other than that, there is a sample implementation (NumericIDGenerator) included in the C:\Program Files\IdeaBlade DevForce\Samples.


Posted By: dpollot44
Date Posted: 13-Jan-2010 at 8:52am
I'm evaluating the software (universal) and that directory does not exist for me.  There are three sub-folders; Documentation, Learning Resources, and SilverLight Assemblies... I would have thought perhaps either of the first two might contain the sample implementations but nope.

Is the code posted somewhere (saving me the time of re-downloading/registering)


Posted By: GregD
Date Posted: 13-Jan-2010 at 11:19am
Between August and now, the Learning Resources were reorganized and the sample implementation of IidGenerator was moved to the following location:

     LearningResources\040_BusObjPersistence\AddingDeleting\Snippets\NumericIdGenerator




Posted By: dpollot44
Date Posted: 13-Jan-2010 at 12:14pm
I forgot to mention that the "LearningResources" folder is empty for me (I had tried to do a quick search for the .cs file and it would have found it there otherwise).  Do I just need to re-download and extract?  Perhaps a different version?


Posted By: dpollot44
Date Posted: 13-Jan-2010 at 12:35pm
I reinstalled.  The full/vs. custom install didn't include the learning units.


Posted By: dpollot44
Date Posted: 13-Jan-2010 at 1:00pm
...And I spoke too soon.  I've reinstalled a couple of times and the learning folder is empty each time.  Can someone just post the sample code (specifically looking for NumericIdGenerator).



Posted By: davidklitzke
Date Posted: 13-Jan-2010 at 2:26pm

I have seen some rare cases where the Learning Resources get installed to C:\MyTutorials or D:\MyTutorials (or some other drive:\MyTutorials).  I think if you look hard enough, you can find the Learning Resources.  It is extremely rare for the Learning Resources not to get installed somewhere on your hard drive.



Posted By: GregD
Date Posted: 13-Jan-2010 at 5:18pm
/* A sample IIdGenerator implementation.
 *
 *  You can use this as-is (almost) or modify as needed.  This is provided as a sample only.
 *
 *  You may want to use an IIdGenerator to generate both temporary and real Id values for
 *  key fields of your Entities.  Note that for tables using keys based on identity or sequence/serial
 *  values the StoreGeneratedIdGenerator provided by the DevForce framework should be sufficient.
 *
 *  Possible customizations -
 *     - change the namespace
 *     - change the class name
 *     - alter IsApplicable() logic for your data source key
 *     - alter GetNextTempId() logic for custom temporary Id values
 *     - alter GetReadIdMap() logic for custom real Id allocation
 *     
 *  Place your IdGenerator class in an assembly which can be deployed on both client and server.
 *
 *  If you implement a custom IIdGenerator, place the assembly name in either the
 *  ProbeAssemblyNames for a given data source key or the ProbeAssemblyNames
 *  at the root of the IdeaBlade Configuration file.  
 *
*/
using System;
using System.Data;
using System.Runtime.Serialization;

using IdeaBlade.Ado;
using IdeaBlade.Core;
using IdeaBlade.EntityModel;

namespace IdeaBladeTest1Model {

  /// <summary>
  /// Sample IIdGenerator implementation.  The class should be marked with the Serializable
  /// or DataContract attribute if you plan to save and restore the EntityCache to/from files.
  /// </summary>
  [DataContract]
  public class NumericIdGenerator : IIdGenerator {

    /// <summary>
    /// An instance of the IIdGenerator will be instantiated by the DevForce framework
    /// on both the client and server.  A public parameterless constructor is required.
    /// </summary>
    public NumericIdGenerator() {
    }

    /// <summary>
    /// Return true if this IIdGenerator should be used with the specified key.
    /// </summary>
    /// <remarks>
    /// In this example we test the key name, but this is for illustration only.  Be sure to
    /// change this code for your implementation.  If you require an IdGenerator but DevForce
    /// can't find an "applicable" one, an exception is thrown.  Called on both client and server.
    /// </remarks>
    public bool IsApplicable(IDataSourceKey dataSourceKey) {
      return dataSourceKey.Name.StartsWith("IdeaBladeTest1");
    }

    /// <summary>
    /// Called by DevForce on the client to retrieve a temporary Id value for the specified column.
    /// </summary>
    /// <remarks>
    /// This example returns negative values starting at -1.  If you need custom temporary Ids then
    /// change this logic as necessary.
    /// Be sure to store all temporary Ids.  The framework will request them in the <see cref="TempIds"/>
    /// property.
    /// </remarks>
    public object GetNextTempId(DataEntityProperty entityColumn) {
      Object id;
      _nextBaseId++;
      long longId = (long) (-1 * _nextBaseId);
      try {
        id = Convert.ChangeType(longId, entityColumn.DataType);
      } catch {
        throw new NotSupportedException("This id generator cannot generate ids of type " + entityColumn.DataType);
      }

      _tempIds.Add(new UniqueId(entityColumn, id));
      return id;
    }  

    /// <summary>
    /// Called by DevForce on the client to retrieve a collection of the temporary Id values generated since
    /// the last <see cref="Reset"/> call.  
    /// </summary>
    /// <remarks>
    /// Be sure to maintain the collection of temporary Ids generated in <see cref="GetNextTempId"/>.
    /// </remarks>
    public UniqueIdCollection TempIds {
     get { return _tempIds; }
    }

    /// <summary>
    /// Return whether the specified Id is a temporary Id generated by this IdGenerator.
    /// </summary>
    /// <remarks>
    /// DevForce will call this on the client to test whether the specified Id is temporary and will require
    /// "fixup" as a real id.  
    /// </remarks>
    public bool IsTempId(UniqueId uniqueId) {
      if (_tempIds == null) {
        return false;
      }
      return _tempIds.Contains(uniqueId);
    }

    /// <summary>
    /// Called by DevForce after an EntityManager.SaveChanges call is performed and all temporary Id values
    /// have been "fixed up" as real Ids.  Use this to clear your temporary Id collection and reset counters.
    /// </summary>
    public void Reset() {
      _tempIds.Clear();
      _nextBaseId = 0;
    }

    /// <summary>
    /// Called by DevForce from the BOS to retrieve "real" Id values for the temporary Ids passed.
    /// </summary>
    /// <remarks>
    /// You can retrieve "real" Ids in any manner you like - this sample shows allocation
    /// of Ids from a single table holding a global sequence value.
    /// You must return a UniqueIdMap from this method containing a real Id value for each
    /// temporary Id.  Note that the UniqueId objects passed in contain information on the
    /// EntityColumn used.  You can use this information to perform more complex Id allocation
    /// if needed.
    /// Because this method is called from the server, and the server is multi-threaded,
    /// you must provide synchronization logic to handle concurrent requests.  In this
    /// sample, a lock is used within the GetNextId logic.
    /// </remarks>
    public UniqueIdMap GetRealIdMap(UniqueIdCollection tempIds, IDataSourceKey dataSourceKey ) {

      UniqueIdMap idMap = new UniqueIdMap();

      long nextLongId = GetNextId(tempIds.Count, dataSourceKey);
      object nextId;

      // Build a UniqueIdMap containing the mapping of temporary to real Id values.
      foreach (UniqueId aUniqueId in tempIds) {
        try {
          nextId = Convert.ChangeType(nextLongId, aUniqueId.Property.DataType);
        } catch {
          throw new NotSupportedException("This id generator cannot generate ids of type " + aUniqueId.Property.DataType);
        }

        idMap.Add(aUniqueId, nextId);
        nextLongId++;
      }

      return idMap;
    }

    #region Server-side custom Id allocation

    /// <summary>
    /// Perform allocation and return the starting next Id value.
    /// This sample disallows Id allocation for more than MaxGroupSize (1000) values
    /// at a time.  It also always allocates 100 new values at a time.
    /// These numbers are arbitrary, and for illustration only.  
    /// </summary>
    private long GetNextId(int count, IDataSourceKey dataSourceKey) {

      // Serialize access to GetNextId - the BOS is multi-threaded and concurrent saves can be in progress.
      lock (__syncLock) {

        // Do some validation before proceeding.
        TraceFns.Assert(count > 0, "GetNextId requires a positive integer as its arg.");

        TraceFns.Assert(count <=  MaxGroupSize,"Cannot allocate more than "
          + MaxGroupSize + " in any one call to GetNextId");

        // Allocate more Ids only if necessary.  This allocates 100 at a time.
        if (__nextId + count > __maxNextId) {
          AllocateMoreIds(count, dataSourceKey);
        }

        long result = __nextId;
        __nextId += count;        // Next time we'll start here.
        return result;
      }
    }

    /// <summary>
    /// Allocate more "real" Id values.  This sample uses a table called NextId with
    /// "Name" and "NextId" columns.  It uses a "global" allocation strategy - that is,
    ///  Id values are not assigned on a table-specific basis, but globally within the application.
    /// </summary>
    private void AllocateMoreIds(int count, IDataSourceKey dataSourceKey) {
      const String sqlSelect = "select NextId from NextId where Name = 'GLOBAL'";
      const String sqlUpdate = "update NextId set NextId={0} where Name = 'GLOBAL' and NextId={1}";

      // Allocate the larger of the two:  amount requested or the default alloc group size.
      count = Math.Max(count, DefaultGroupSize);

      AdoHelper adoHelper = GetAdoHelper(dataSourceKey);
      IDbConnection aConnection = adoHelper.CreateDbConnection(true);
      aConnection.Open();

      using (aConnection) {
        IDbCommand selectCommand =  adoHelper.CreateDbCommand(aConnection);
        IDbCommand updateCommand = adoHelper.CreateDbCommand(aConnection);

        for (int trys = 0 ; trys <= MaxTrys ; trys++) {
          
          selectCommand.CommandText = sqlSelect;    
          IDataReader aDataReader = selectCommand.ExecuteReader();
          if (!aDataReader.Read()){
            throw new ApplicationException("Unable to locate 'NextId' record");
          }

          Object tmp = aDataReader.GetValue(0);
          long nextId = (long) Convert.ChangeType(tmp, typeof(Int64));
          long newNextId = nextId + count;
          aDataReader.Close();

          // Update the table to reflect the new NextId value to be assigned next time.
          updateCommand.CommandText = String.Format(sqlUpdate, newNextId, nextId);
         
          // If only one record was affected - we're ok; otherwise try again.
          if (updateCommand.ExecuteNonQuery() == 1) {
            __nextId = nextId;
            __maxNextId = newNextId;
            return;
          }
        }
      }
      throw new ApplicationException("Unable to generate a new id");
    }

    /// <summary>
    /// Retrieve an AdoHelper to use in data access.  This sample issues
    /// select and update commands to the database, using the AdoHelper.
    /// </summary>
    private AdoHelper GetAdoHelper(IDataSourceKey dataSourceKey) {

      // Option 1 - if you want to reference both IdeaBlade.EntityModel.Edm.v4
      //  and IdeaBlade.Rdb.v4 assemblies.
      IdeaBlade.EntityModel.Edm.EdmKey edmKey =
        dataSourceKey as IdeaBlade.EntityModel.Edm.EdmKey;
      RdbKey rdbKey = edmKey.RdbKey as RdbKey;
      return rdbKey.AdoHelper;


      // Option 2 - you might not want to reference the IdeaBlade.EntityModel.Edm.v4 assembly on your
      //  client (since it in turn references Entity Framework assemblies).  You could instead use
      //  a little reflection.
      //      Type t = InternalFns.GetIdeaBladeType("IdeaBlade.EntityModel.Edm.v4.EdmKey", true);
      //      RdbKey rdbkey = t.GetProperty("RdbKey").GetValue(dataSourceKey, null) as RdbKey;
      //      return rdbkey.AdoHelper;


      // Option 3 - You can create separate client-side vs. server-side IdGenerator implementations.
      //  Contact IdeaBlade for more information.

    }
    #endregion

    // Client-side variables.
    [DataMember]
    private UniqueIdCollection _tempIds = new UniqueIdCollection();
    [DataMember]
    private int _nextBaseId;

    private const int  MaxTrys           = 3;       // Fail after 3 unsuccessful allocation attempts.
    private const int  DefaultGroupSize  = 100;     // Allocate 100 new Ids at a time.
    private const int  MaxGroupSize      = 1000;    // Only allow 1000 Ids max in a call.

    // Server-side variables.
    private static object __syncLock = new object();
    private static long __nextId       = 0;
    private static long __maxNextId    = 0;
   
  }
}
 


Posted By: pucsoftware
Date Posted: 03-Feb-2010 at 8:21am
In DevForce v5.2.4.2 on Windows 7 we found the sample class, both C# & VB versions, installed here:
 
C:\Users\Public\Documents\DevForce\Learning Resources\040_BusObjPersistence\AddingDeleting\Snippets\NumericIdGenerator
 
This may be useful if you're looking for the VB version.


-------------
puctx


Posted By: tj62
Date Posted: 03-Jan-2011 at 7:55am
I have searched all over the place on my computer and it is not there the LearningResources folder does not exist. Except I find it for an old 2009 installatoin at:
    C:\Program Files\IdeaBlade DevForce\Learning Resources
But the current installatoin is at:
    C:\Program Files\DevForce 2010
where there is no Learning Resources folder at all.
 
Where in heck is it?


Posted By: davidklitzke
Date Posted: 03-Jan-2011 at 9:45am

If you are looking at DevForce 2009, you can find the files at a location such as:

 C:\Program Files\IdeaBlade DevForce\Learning Resources\040_BusObjPersistence\AddingDeleting\Snippets\NumericIdGenerator

If you are looking at DevForce 2010, the files are not where you might expect them to be (i.e., in the "030_BusObjPersistence\AddingDelecting" folder).  However you can find both C# and VB versions in the "030_BusObjPersistence\_MiniDemos" folder.




Print Page | Close Window