/////////////////////////////////////////////////////////// // IntegrationMap.cs // Implementation of Class IntegrationMap // CSLA type: Editable Child // Created on: 09-Feb-2006 // Object design: John // Coded: John 09-Feb-2006 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using GZTW.Data; using CSLA; using System.Threading; using CSLA.Security; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.IO; namespace GZTW.AyaNova.BLL { /// /// Map to tie an integration application's data /// to AyaNova object records /// /// For example: /// In QuickBooks integration for the optional /// QBI product this object maps /// between QuickBooks objects and their /// corresponding AyaNova object. /// [Serializable] public class IntegrationMap : BusinessBase { #region Attributes //Kept for compatibility reasons //Users will have their own security for this stuff private bool bReadOnly=false; private Guid mID; private Guid mCreator; private Guid mModifier; private SmartDate mCreated; private SmartDate mModified; /// /// ID of parent integration object /// private Guid mIntegrationID; /// /// ID of AyaNova Object /// private Guid mRootObjectID=Guid.NewGuid(); private RootObjectTypes mRootObjectType; private string mForeignID=null; private string mName=""; private SmartDate mLastSync; private object mMapObject=null; private string mForeignCheckSum=""; private string mAyaNovaCheckSum=""; #endregion #region Constructor private IntegrationMap() { //Child object MarkAsChild(); //New ID mID = Guid.NewGuid(); //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified=new SmartDate(); mCreator=Guid.Empty; mModifier=Guid.Empty; RootObjectID=Guid.Empty; this.RootObjectType=RootObjectTypes.Nothing; ForeignID=""; mLastSync = new SmartDate(DBUtil.CurrentWorkingDateTime); } #endregion #region Business Properties //---Common properties /// /// Initial created date of this object /// public string Created { get { return mCreated.ToString(); } } /// /// User ID of who initially created this object /// public Guid Creator { get { return mCreator; } } /// /// Last modified date of this object /// public string Modified { get { return mModified.ToString(); } } /// /// User ID of who last modified this object /// public Guid Modifier { get { return mModifier; } } /// /// Unique ID of this object /// public Guid ID { get { return mID; } } //---IntegrationMap specific properties /// /// ID of parent integration object /// public Guid IntegrationID { get { return mIntegrationID; } } /// /// AyaNova object ID /// public Guid RootObjectID { get { return mRootObjectID; } set { if(bReadOnly) ThrowSetError(); else { if(mRootObjectID!=value) { mRootObjectID = value; BrokenRules.Assert("RootObjectID","Error.Object.RequiredFieldEmpty,IntegrationMap.Label.RootObjectID","RootObjectID",value==Guid.Empty); MarkDirty(); } } } } /// /// AyaNova object type /// public RootObjectTypes RootObjectType { get { return mRootObjectType; } set { if(bReadOnly) ThrowSetError(); else { if(mRootObjectType!=value) { mRootObjectType = value; BrokenRules.Assert("RootObjectType","Error.Object.RequiredFieldEmpty,IntegrationMap.Label.RootObjectType","RootObjectType",value==RootObjectTypes.Nothing); MarkDirty(); } } } } /// /// Set/get Foreign ID /// This is the integration object ID /// Required, 255 ASCII characters max /// public string ForeignID { get { return mForeignID; } set { if(bReadOnly) ThrowSetError(); else { if(mForeignID!=value) { mForeignID = value; BrokenRules.Assert("ForeignIDRequired","Error.Object.RequiredFieldEmpty,IntegrationMap.Label.ForeignID","ForeignID",value.Length==0); BrokenRules.Assert("ForeignIDLength", "Error.Object.FieldLengthExceeded255,IntegrationMap.Label.ForeignID","ForeignID",value.Length>255); MarkDirty(); } } } } /// /// Set/get Integration object's name /// 255 unicode characters max /// public string Name { get { return mName; } set { if(bReadOnly) ThrowSetError(); else { if(mName!=value) { mName = value; BrokenRules.Assert("NameLength", "Error.Object.FieldLengthExceeded255,IntegrationMap.Label.Name","Name",value.Length>255); MarkDirty(); } } } } /// /// DateTime field indicating the last time integration object was synchronized /// Set by the integrating application. /// /// Implementers may use this date as required, it's purpose is to aid in /// synchronization and use is optional /// /// If a null or non existant date is desired set this value to /// System.DateTime.MinValue as that is the standard used in AyaNova for null dates /// /// public DateTime LastSync { get { return mLastSync.Date; } set { if (bReadOnly) ThrowSetError(); else { if (mLastSync.Date != value) { mLastSync.Date = value; MarkDirty(); } } } } /// /// Object for use by integration application store /// with individual map object /// /// You can store any data you wish in this object, it is /// serialized to and from the database in a binary blob / image field. /// /// Typically this would be used to store data about an individual mapped object that is /// application specific I.E. create a serializable class or structure to contain /// data and store / retrieve via this field. /// /// Don't go overboard with this object it *is* stored in the database and /// should not be used to store huge binary objects, this will /// only slow down your application and bloat the users database un-necessarily. /// /// 32k or less is a good rule of thumb /// /// We may enforce this to 32k or less in future so consider carefully keeping under the /// 32K limit. If you need to go over this limit regularly then those /// objects should be stored with the application that is integrating /// outside of AyaNova. I.E. in a separate database or file system. /// /// public object MapObject { get { return mMapObject; } set { if (bReadOnly) ThrowSetError(); else { if (mMapObject != value) { mMapObject = value; MarkDirty(); } } } } /// /// Set/get Integration object's AyaNovaCheckSum /// 255 ascii characters max /// /// This is an optional field that can be used to store /// a checksum or any string value. It's intended use /// is to store a checksum of the fields in the AyaNova /// object that are of interest if they are changed. /// /// So, for example, if you were interested in knowing if /// an AyaNova object had a specific set of fields changed /// since originally being added to this collection /// you might generate a checksum on the /// fields in question and store it here, then you can later /// regenerate a checksum on that object and compare it to this /// value to determine quickly if any of the fields of interest /// have changed. /// /// If you just want to know if any part of the object was changed /// then you would normally track the Modified date of the AyaNova object /// and compare it with the lastsync date here, this field is intended /// to give more granular control if you are interested only in specific /// fields that might have changed. /// /// This could also be useful for comparing objects to see if a select /// set of fields are identical /// public string AyaNovaCheckSum { get { return mAyaNovaCheckSum; } set { if(bReadOnly) ThrowSetError(); else { if(mAyaNovaCheckSum!=value) { mAyaNovaCheckSum = value; BrokenRules.Assert("AyaNovaCheckSumLength", "Error.Object.FieldLengthExceeded255,IntegrationMap.Label.AyaNovaCheckSum","AyaNovaCheckSum",value.Length>255); MarkDirty(); } } } } /// /// Set/get Integration object's ForeignCheckSum /// 255 ascii characters max /// /// This is an optional field that can be used to store /// a checksum or any string value. It's intended use /// is to store a checksum of the fields in the Foreign /// object that are of interest if they are changed since /// the point they were originally linked but you don't want /// to track any changes to the object, only specific ones /// to a limited set of data. /// /// (for a more general change tracking method you might compare /// the last sync date instead) /// /// This could also be useful for comparing objects to see if a select /// set of fields are identical /// /// public string ForeignCheckSum { get { return mForeignCheckSum; } set { if(bReadOnly) ThrowSetError(); else { if(mForeignCheckSum!=value) { mForeignCheckSum = value; BrokenRules.Assert("ForeignCheckSumLength", "Error.Object.FieldLengthExceeded255,IntegrationMap.Label.ForeignCheckSum","ForeignCheckSum",value.Length>255); MarkDirty(); } } } } /// /// Throw an error when a read only user /// tries to set a property /// (this should normally never be called unless someone is using the developer api since the UI /// should prevent it from happening initially) /// private void ThrowSetError() { throw new System.Security.SecurityException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.IntegrationMap") ) ); } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "IntegrationMap" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false; IntegrationMap c=(IntegrationMap)obj; return mID==c.mID; } /// /// /// /// public override int GetHashCode() { return ("IntegrationMap" + mID).GetHashCode(); } #endregion #region Static methods /// /// Create item /// Create a new integration map child object /// /// Parent Integration object /// New Item internal static IntegrationMap NewItem(Integration obj) { // if(AyaBizUtils.Right("Object.IntegrationMap")>(int)SecurityLevelTypes.ReadOnly) // { IntegrationMap child=new IntegrationMap(); child.mIntegrationID=obj.ID; return child; // } // else // throw new System.Security.SecurityException( // string.Format( // LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), // LocalizedTextTable.GetLocalizedTextDirect("O.IntegrationMap"))); // } /// /// Retrieve item /// /// Data reader /// item from database internal static IntegrationMap GetItem(SafeDataReader dr) { // if(AyaBizUtils.Right("Object.IntegrationMap")>(int)SecurityLevelTypes.NoAccess) // { IntegrationMap child = new IntegrationMap(); child.Fetch(dr); return child; // } // else // throw new System.Security.SecurityException( // string.Format( // LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), // LocalizedTextTable.GetLocalizedTextDirect("O.IntegrationMap"))); } #endregion #region DAL DATA ACCESS /// /// Fetch from db /// /// private void Fetch(SafeDataReader dr) { //Standard items mCreated=DBUtil.ToLocal(dr.GetSmartDate("aCreated")); mCreator=dr.GetGuid("aCreator"); mModified=DBUtil.ToLocal(dr.GetSmartDate("aModified")); mModifier=dr.GetGuid("aModifier"); //IntegrationMap specific parameters mID=dr.GetGuid("aID"); mIntegrationID=dr.GetGuid("aIntegrationID"); RootObjectID=dr.GetGuid("aRootObjectID"); RootObjectType=(RootObjectTypes)dr.GetInt16("aRootObjectType"); ForeignID=dr.GetString("aForeignID"); Name=dr.GetString("aName"); mLastSync=DBUtil.ToLocal(dr.GetSmartDate("aLastSync")); //Get the MapObject //Get the layout size int mMapObjectSize = dr.GetInt32("aMapObjectSize"); //Is there anything to load? if (mMapObjectSize > 0) { BinaryFormatter bformatter = new BinaryFormatter(); bformatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; byte[] obData = new Byte[mMapObjectSize]; //retrieve the bytes dr.GetBytes("aMapObject", 0, obData, 0, mMapObjectSize); MemoryStream mstream = new MemoryStream(obData); this.mMapObject = (object)bformatter.Deserialize(mstream); } else this.mMapObject = null; //Get access rights level //bReadOnly=AyaBizUtils.Right("Object.IntegrationMap")<(int)SecurityLevelTypes.ReadWrite; MarkOld(); } /// /// Persist object to database /// /// Parent integratin object /// Parents transaction object internal void Update(Integration obj,IDbTransaction tr) { //No need to update if there is nothing changed if(!this.IsDirty) return; //get modification time temporarily, if update succeeds then //set to this time System.DateTime dtModified = DBUtil.CurrentWorkingDateTime; // If not a new record, check if record was modified //by another user since original retrieval: if(!IsNew) DBUtil.CheckSafeToUpdate(this.mModified.Date,this.mID,"aIntegrationMap"); #region Delete if(IsDeleted) { if(!IsNew) { //Delete DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aIntegrationMap WHERE aID = @ID;"); cmDelete.AddInParameter("@ID",DbType.Guid,this.mID); DBUtil.DB.ExecuteNonQuery(cmDelete, tr); } MarkNew(); return; } #endregion #region Add / Update DBCommandWrapper cm = null; if(IsNew)//Add or update? cm=DBUtil.GetCommandFromSQL( "INSERT INTO aIntegrationMap (aRootObjectID, aRootObjectType, aIntegrationID, aForeignID, " + "aName, aMapObjectSize, aMapObject, " + "aLastSync,aID, aCreated, aModified, aCreator, aModifier) " + "VALUES (@RootObjectID,@RootObjectType, @IntegrationID,@ForeignID, " + "@Name, @MapObjectSize, @MapObject, " + "@LastSync, @ID, @Created, @Modified, @CurrentUserID,@CurrentUserID)" ); else cm=DBUtil.GetCommandFromSQL( "UPDATE aIntegrationMap SET " + "aRootObjectID=@RootObjectID,aRootObjectType=@RootObjectType, aIntegrationID=@IntegrationID,aForeignID=@ForeignID, " + "aName=@Name, aMapObjectSize=@MapObjectSize, aMapObject=@MapObject, " + "aLastSync=@LastSync, aModifier = @CurrentUserID, " + "aModified=@Modified WHERE aID=@ID" ); //IntegrationMap fields cm.AddInParameter("@ID",DbType.Guid,mID); cm.AddInParameter("@IntegrationID",DbType.Guid,mIntegrationID); cm.AddInParameter("@RootObjectID",DbType.Guid,mRootObjectID); cm.AddInParameter("@RootObjectType",DbType.Int16,(int)mRootObjectType); cm.AddInParameter("@ForeignID",DbType.String,mForeignID); cm.AddInParameter("@Name",DbType.String,mName); cm.AddInParameter("@LastSync",DbType.DateTime,DBUtil.ToUTC(mLastSync).DBValue); //MapObject serialize: if (mMapObject != null) { MemoryStream ms = new MemoryStream(); BinaryFormatter b = new BinaryFormatter(); b.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple; b.Serialize(ms, mMapObject); cm.AddInParameter("@MapObjectSize", DbType.Int32, ms.Length); cm.AddInParameter("@MapObject", DbType.Object, ms.GetBuffer()); } else { cm.AddInParameter("@MapObjectSize", DbType.Int32, 0); cm.AddInParameter("@MapObject", DbType.Object, new byte[1]); } //Standard fields cm.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cm.AddInParameter("@Created",DbType.DateTime, DBUtil.ToUTC(mCreated.Date)); cm.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); DBUtil.DB.ExecuteNonQuery(cm, tr); MarkOld();//db is now synched with object //Successful update so //change modification time to match this.mModified.Date=dtModified; #endregion } #endregion }//end IntegrationMap }//end namespace GZTW.AyaNova.BLL