Among the first pieces of advice I received when I started working with SalesLogix 7.2 Web Client was to create a new Package for my custom entities. I wish I could remember where I got that advice, because there is a piece missing. That is, in the process of creating my custom entities and forms I found that the custom entities CRUD functions were not functioning properly. I was receiving messages about NHibernate mapping exceptions like "Unknown Entity Class". When I created those entities in the SalesLogix Application Entities package, they worked fine.
- I presume there is somewhere I can register the assembly and use my own Package. Does anyone know how?
That said, and I still intend to write this as an article to submit, here is the process I'm using:
- Create Table in Administrator.
- Create Entity in Application Architect.
This is where previous advice I had read was to create a separate package in Application Architect and add your Entities to it, but until I see a solution to the problem of how to make NHibernate aware of those Entities on deployment, I plan to stick with SalesLogix Application Entities.
- Create Relationship Properties.
I'm not quite comfortable with the relationships yet. At this point I suggest creating the relationships from both ends. That is, create the relationship from the child to the parent and then the parent to the child, only completing the top section of each.
- What is the current best practice on creating relationships?
- Build Web Platform.
This is another place where having worked with RC1 through the Gold release, I have gotten in the habit of saving often and rebuilding the interfaces and web platform every chance I get.
- Create a Form for the new Entity.
Select properties of the Entity to show on the form. Position the controls, etc.
- Add a button to the Form to save the changes.
The Save button requires a code snippet, but the one in the Magic Carpets example looks out of date as the MagicCarpets collection added to the parent Entity doesn't function the way it does in the sample code. So, assuming the parent Entity is Contact as it was in the sample, here is the amended code without the refresh trigger:
if (this.BindingSource != null) { Sage.Entity.Interfaces.ICustomEntity customEntity = this.BindingSource.Current as Sage.Entity.Interfaces.ICustomEntity; Sage.Entity.Interfaces.IContact contact = GetParentEntity() as Sage.Entity.Interfaces.IContact; if (contact != null) { customEntity.Contact = contact; } customEntity.Save(); }
The Magic Carpet example notes that the relationship to the parent entity has to be set here because if you set it earlier it will be lost in post back. It suggests that this will be corrected in future releases, but I'm still seeing this behavior in the Gold release.
- Does the Gold release fix this, and I just need to check my code or is this still an issue? It looks to me like the entity is dumped at every post back, but I'm new to dealing with NHibernate, so maybe I'm missing something...
- Save and Build Web Platform.
- Create a Custom Form.
I used the code generated .ascx from the above Quick Form as a template, but you could start from scratch and skip the Quick Form if you wanted.
- Create a folder for your forms under SupportFiles/SmartParts in the Portal Manager or Webroot/common/SmartParts in Virtual File System Explorer.
- Create a sub-folder App_LocalResources.
- Import custom .ascx files ("Add Existing Files...").
- In Portal Manager, select the Page from which you want to launch a Form.
- Add the form as a Smart Part.
- Set the Smart Part ID, Title, and Description
- Set the Target Workspace according to where the form should be displayed.
- Main Content
- Dialog Workspace
- Tab Control
- Navigation Bar
- Toolbar
- Set Show In Mode according to when the form should be displayed.
- Detail: When browsing the items of the parent Entity.
- Insert: When creating an item of the parent Entity.
- List: When viewing a list of the parent Entity items.
- Save and Build Web Platform.
- If needed, add code to display the Smart Part.
Ex. I have edited the OpportunitySalesProcess code DoWebForm function to use DialogService to display the appropriate Smart Part based on which Step in which Process link was clicked.
private string DoWebForm(ISalesProcessAudit spAudit) { string result = string.Empty; if (DialogService != null) { switch (spAudit.Name) { case "Client Satisfaction Report": switch (spAudit.StepName) { case "Audit Report": DialogService.SetSpecs(50, 50, 800, 600, "ClientSatReportCompliance"); DialogService.ShowDialog(); break; case "Report Entry": break; } break; case "Inactive Status Request": switch (spAudit.StepName) { case "Audit": DialogService.SetSpecs(50, 50, 800, 600, "InactiveStatusRequestAudit"); DialogService.ShowDialog(); break; case "Initial Request": DialogService.SetSpecs(50, 50, 800, 600, "InactiveStatusRequestEntry"); DialogService.ShowDialog(); break; } break; } result = string.Empty; } return result; }
I'll preserve the errors from my original post below. I'll keep updating this process as I figure out what I'm doing wrong. Things still aren't as smooth as it seems they ought to be, but hopefully some of you can help me understand what's up. Eric
Error received when attempting to save Entity in a separate package:
NHibernate.MappingException was unhandled by user code Message="Unknown entity class: UroMed.SalesLogix.Entities.UroInactiveStatusReq" Source="NHibernate" StackTrace: at NHibernate.Impl.SessionFactoryImpl.GetEntityPersister(Type theClass) at NHibernate.Impl.SessionImpl.GetClassPersister(Type theClass) at NHibernate.Impl.SessionImpl.GetEntityPersister(Object obj) at NHibernate.Impl.SessionImpl.SaveWithGeneratedIdentifier(Object obj, CascadingAction action, Object anything) at NHibernate.Impl.SessionImpl.Save(Object obj) at UroMed.SalesLogix.Entities.UroInactiveStatusReq.Save() at ASP.InactiveStatusRequestEntry.SubmitButton_Click(Object sender, EventArgs e) in c:\inetpub\wwwroot\SalesLogix_Client\SmartParts\InactiveStatusRequest\InactiveStatusRequestEntry.ascx:line 322 at System.Web.UI.WebControls.Button.OnClick(EventArgs e) at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Error received when attempting to create Entity in separate package:
[RepositoryException: Mapped NHibernate type not found] Sage.Platform.NHibernateRepository.NHibernateRepository..ctor(Type persistentType) +163 Sage.Platform.NHibernateRepository.NHibernateRepository`1..ctor() +54 [TargetInvocationException: Exception has been thrown by the target of an invocation.] System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck) +0 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache) +103 System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache) +261 System.Activator.CreateInstance(Type type, Boolean nonPublic) +66 Sage.Platform.EntityFactory.GetRepository(Type type) +139 Sage.Platform.EntityFactory.GetRepository() +84 Sage.Platform.EntityFactory.Create() +50 ASP.InactiveStatusRequestEntry.OnLoad(EventArgs e) in c:\inetpub\wwwroot\SlxClient\SmartParts\InactiveStatusRequest\InactiveStatusRequestEntry.ascx:211 System.Web.UI.Control.LoadRecursive() +47 System.Web.UI.Control.AddedControl(Control control, Int32 index) +2113301 System.Web.UI.ControlCollection.Add(Control child) +146 Sage.Platform.WebPortal.Workspaces.WebWorkspaceBase`2.Show(Object smartPart, ISmartPartInfo smartPartInfo) +268 Sage.Platform.WebPortal.Workspaces.DialogWorkspace.addSmartParts() +103 Sage.Platform.WebPortal.Workspaces.DialogWorkspace.OnPreRender(EventArgs e) +31 System.Web.UI.Control.PreRenderRecursiveInternal() +77 System.Web.UI.Control.PreRenderRecursiveInternal() +161 System.Web.UI.Control.PreRenderRecursiveInternal() +161 System.Web.UI.Control.PreRenderRecursiveInternal() +161 System.Web.UI.Control.PreRenderRecursiveInternal() +161 System.Web.UI.Control.PreRenderRecursiveInternal() +161 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1360
|