-
Dynamics CRM 3.0 Customization: The basics
One thing that I keep getting reminded of while entering into various CRM customization projects is that there is almost always two different ways to do the same thing in CRM 3.0. Off the top of my head, I can think of the following methods that can be used to customize a CRM 3.0 installation:
1) Adding Entities and/or Attributes ( tables and columns for normal folks ).
2) Modifying the layout and display of existing CRM Entities.
3) Workflow rules.
4) Custom applications that utilize the CRM SDK including: Web pages, .NET assemblies, etc.
5) Callouts.
6) Connecting line of business applications and CRM together through custom code ( #4 and #5 ).
7) Custom data entry form actions implemented through JavaScript.
And what does this mean to a normal human being? Simply this:
1) Document your requirements
2) Review the possible implementation issues and alternatives
3) How much time and money will be required to implement each alternative.
4) Choose the solution that best matches your requirements.
5) When in doubt: test in a development environment.
So just what in the heck are you talking about?
Well, let's review the a couple of situations that I've run up against and see what comes out.
Scenario 1: Linking a Lender with a Home Buyer.
We created a proof of concept for a local home builder and within the system, we had to record all of the contact information for any company and/or individual associated with a particular home: Home buyer, lender, title company, etc.
Issue 1:
So were do we store the contact information for these people?
Alternative 1:
Store them as Accounts and Contacts and link those back to the Home Buyer account and contact.
Alternative 2:
Create custom entities for each of the contact types and link those back to the Home Buyer.
Solution 1:
In this particular case, we had to choose Alternative 2 because that was the only physical way we could link everyone to everyone. CRM 3.0 does not allow you to create multiple relationships between Entities and since Account and Contact are already linked, a secondary relationship could not be created. Separate Entities were created for each company type and company individual ( i.e., Lender and Lender Contact ). This allowed us to link a contact from each custom Entity to the Home Buyer ( Contact ).
Scenario 2: Build a new Entity or customize an existing Entity.
This will be the biggest decision you will make when customizing CRM. If you have reviewed any of the CRM customization capabilities, you will know that it is very easy to add new fields and new tabs to the data entry forms.
But is that the right thing to do, or would it be better to separate this new set of information into its own Entity and link that Entity to the Account, Contact, etc.?
In most cases, if you just have a few fields that need to be added, you can just add them to the existing Entity and be done with it. Creating a new tab is optional, of course.
I think the main decision point is whether or not you need multiple records. A multi-record solution would almost always require a secondary Entity that you link back to its parent. You can even do things like display that information within an iFrame on the data entry form so the user can see both the parent's information and the secondary information on the same screen.
Note: It should be noted that some CRM 3.0 entities do not easily lend themselves to customization. Things like Quotes, Orders, etc.
Conclusion:
It is very seldom that I run into an design requirement that can't be overcome using one of the methods outlined at the beginning of this article. It usually all boils down to the amount of time and money you wish to spend. An objective review of all of the facts is, in many cases, quite eye-opening when you consider needs vs. costs.
Customization, Dynamics CRM 1,366 views -
Interesting Site of the Week: Digication
This evening, I was listening to the latest edition of Inside the Net with Amber MacArthur ( from TWiT.tv ) as they were discussing a new education site called Digication.
Not only did I get to hear a human being [ Leo Laporte ] use the word matriculate in a sentence, but I also got to hear a bit about a [ not so new ] site created for Educators and their Students.
I find this site absolutely fascinating because I just had this conversation with a friend of mine, a private-school teacher. She needs the ability to share her course materials with her students so they can access the information from home.
This site can do this – and mostly for free. The first 1,000 users are free with a nominal charge for additional users.
In addition, Digication actually opens up what is really a social network where the teachers and students can discuss, on-line, the class and materials.
About Digication:
Digication represents an entirely new concept in educational software. Easier to master. Simpler to use. With all the connectivity, file sharing and e-portfolio tools educators and students want. Designed by educators to serve the core needs of educators, Digication Campus & Spotlight open the lines of communications by combining elements of social networking and learning content management systems. The software allows users to create a community that can learn and grow both inside and outside the classroom.
Simple by design, Digication Campus & Spotlight steer clear of superfluous features and extended training, and instead relies on an intuitive interface that can be learned in minutes. Educators can create a simpler, more appealing and more cost effective web-based solution for creating, managing, sharing and accessing educational content.
Digication was founded by faculty at the Rhode Island School of Design in Providence, RI. In an effort to bring educators a simple way to communicate with their students, the founders designed a network community intended to be populated with high quality users and content simplifying the latest developments in technology.
If you are an educator, or know one, I would strongly advise that you point them to both the TWiT Podcast and the Digication site itself.
And for the record, I'm just a little more than disappointed that I didn't think of this first. :)
Misc 2,374 views -
Driving Dynamics CRM 3.0 User Adoption
Gaining user acceptance and adoption of Dynamics CRM can, of course, be greatly increased with proper instruction and training.
I have begun to notice a pattern in acceptance should you be installing CRM into an organization that does not currently utilize Outlook, or uses it minimally.
If the user isn't familiar and comfortable with Outlook, installing the CRM Outlook client can confuse the heck out of them. This is caused by the fact that once the Outlook client is installed, the user now has at least two different methods to do many things. And, if they don't know where Outlook ends, and where the CRM client begins, it can lead to more than a little bit of frustration as they attempt to determine the correct way to do something.
But doesn't everyone use Outlook?
Not as much as you think, especially in smaller organizations, and especially if they don't have Exchange installed. Either they use Outlook Express for email or use Outlook and then, only for email. That means that things many of us take for granted, like: Contacts, Scheduling, and Shared or Group Calendars are totally new and different. New and different many times is translated into "scary" and scary is bad.
Working through the issues
Here is one approach that I think will work in many organizations who make little or no use of Outlook.
1) Take time to know and understand the product knowledge-level of user community.
2) Perform a phased implementation and get the user working and productive with Outlook before CRM is implemented.
3) Have you or your staff be physically present during this initial phase so that people can ask stupid and embarrassing questions.
Note: There are no such things as stupid and embarrassing questions, but people still think they exist.
4) Perform a simple, quarter or half-day group training session so people can get an exposure to the product.
5) Engage with the users one-on-one, to provide personalized responses to questions and issues.
People will generally react much better to personal coaching than group training and will tend to ask better and more questions when outside of the group setting.
6) By this point you have probably finished your CRM installation, configuration, and customization activities and it is now time to roll-out the CRM Outlook client.
7) Repeat steps 3 through 5 and outline the differences between Outlook and CRM and discuss in detail how the two products work together.
8) Have users keep a notepad to document questions and concerns as they use the system.
9) Perform frequent visits to each user's office to review and address any questions and concerns they may have document in their notepad.
While these steps may not handle everything you encounter, I think it covers most of the issues that I've seen in the past couple CRM implementations.
If you have experiences of your own that you would like to share, please leave a comment.
Dynamics CRM, Installation, Outlook Client 2,146 views -
CRM Outlook Sync issue and why I owe Larry Lentz lunch
One of the users at one of my customers starting having Outlook start up and hang – maximizing the CPU while doing so.
I tried removing and reinstalling the Outlook Desktop Client several times but could never figure out what in the world was causing Outlook to hang like it was.
After searching around for a bit, I found an article on Larry Lentz's blog regarding a similar-sounding issue. It was solved by finding a CRM contact record containing bad data, and deleting the contents of the field where the bad data existed.
After reinstalling the Outlook client I displayed the synchronization status and saw that it was only syncing a single task between CRM and Outlook. Hmm, I thought.
Using the CRM Web Client, I closed the task as completed and restarted Outlook. After dealing with an error message, I noticed that the CPU issue had corrected itself.
Evidently, as Larry had found, there was something in that Task that was causing Outlook to freak out.
Thanks for the article Larry. Lunch is on me next time you're in Dallas ( or I'm in SA ).
Dynamics CRM, Outlook Client 2,339 views -
Extending Microsoft CRM 3.0 Course Released
Microsoft has released the final set of training materials required to get your CRM certifications up to the 3.0 level.
Extending Microsoft CRM 3.0, Course 8531
This material will assist you in preparation for the Extending Microsoft CRM 3.0 exam.
Good luck.
Dynamics CRM 1,214 views -
Revised: Displaying Contact Information Inside an iFrame
This is a revision to an article from March, 2006.
My current project developed a requirement to display the Contact information on a tab on the Opportunity Entity. Pretty simple, I thought, just create a new tab, throw on an iFrame and put a reference to one of the CRM pages that will display the contact for me.
Pretty simple, on paper. Execution turned it into something quite different that took me much longer that I would have hoped. Anyway, here is the solution:
1. Create a new tab and insert an iFrame.
2. Set the URL field to:
http://server/_forms/readonly/readonly.aspx?obTypeCode=1&id= Which will make the form look like this:
3. In the Form’s OnLoad Event, place the following code:
if (crmForm.all.customerid.DataValue[0].id != null) { var ContactURL = "http://crm/_forms/readonly/readonly.aspx?objTypeCode=2&id=" crmForm.all.IFRAME_ContactInfo.src = ContactURL + crmForm.all.customerid.DataValue[0].id; } This code will add the GUID or Unique ID to the URL for your iFrame so that when you click on the Contact Info tab, you see the contact information for the Contact associated with the Opportunity.
Notes:
It is very important that the objTypeCode parameter match the CRM Entity type that you wish to display. For instance, if you wish to display a Contact in the iFrame, objTypeCode would equal 2. If you wish to display an Account, objTypeCode would equal 1. For a complete list of CRM Object Type Codes, visit the following link.
JavaScript is also case-sensitive, so make sure that you spell the parameter names exactly as you see above.
Conclusion:
It took me longer than usual because the information in the SDK was incorrect. Thanks to Matt Whittemann for instructions to get around that issue and to Ronald Lemmen for information on how to display the read-only form.
References:
Dynamics CRM 3.0 SDK: Client Programming, iFrame Support
Dynamics CRM 3.0 SDK: Client Programming, URL Addressable Forms
Dynamics CRM 3.0 SDK: Client Programming, Lookup Field Types
New Example of Javascript OnChange Code For CRM 3.0
Customization, Dynamics CRM 3,490 views -
AJAX/Atlas UpdateProgress Control
Scott Guthrie posted an article today discussing the use of the UpdateProgress control that is used to display a progress indicator while you are performing some action via AJAX. Here is an example of an indicator:
Included in the article were links to several sites were that provide alternatives to the standard Atlas progress icon ( an animated GIF file ) that really allow you to customize the appearance of your.
One of the links, http://www.ajaxload.info/, allows you to create custom animations using a variety of user-defined styles and colors.
Check it out.
Development 7,039 views -
The saga of .NET, DataAdapter.Update, and multiple tables
What a good waste of half of a day of my life. Actually, it wasn't even that good – but it was wasted.
I am working on a utility that includes a function to move data between databases so I need to copy data from one DataSet to another then merge that data into an existing set of DataTables and Update the physical database with the changes.
Believe it or not, this is not the simple process that you would think. I ran into all sorts of strange issues that either generated an error or didn't work ( no database update ).
Background
If you are in the practice of retrieving multiple tables using a single SQL Adapter ( Or OLE, for that matter ), you need to take into account the possibility that you may need to update those tables at some point in the future. I discovered, thanks to Chris' article, that the DataSet.Merge and DataAdapter.Update do not function very well when you have retrieved multiple tables using a single query using multiple selects, like this: "SELECT * FROM Customers; SELECT * FROM Orders"
Issues
There were at least three separate issues that I ran into:
1) RowState not being set in such a way that the Update command thought there was anything to do.
2) The Adapter getting very confused about which table we were actually trying to update.
3) My physical database tables needed to have a Primary Key defined.
What made this so very complicated, at least to me, was the fact that there is so little code involved here, really just a hand-full of lines, so which one was causing the exact issue or issues?
Solutions
After wasting most of the afternoon on the code and Googling for what seemed like 200 pages and posts, I finally tracked down the following article by Chris Pietschmann:
Fill DataSet with multiple Tables and update them with DataAdapter
The solution, as Chris mentions, is to create a function that will retrieve a single table then update the data in that table alone. That was indeed the solution. Here is the function I created to do the work ( exception handling removed for readability ):
1. public int CreateMigrateDataset(OleDbConnection dbConnDest, ref DataSet ds, int ID) 2. { 3. string sourceTableName = TABLE_NAMES[ID]; 4. string destTableName = MIGRATE_TABLE_NAMES[ID]; 5. DataSet dsDest = new DataSet(); 6. string queryString2 = String.Format("select * from {0}; ", destTableName); 7. 8. OleDbDataAdapter daDest = new OleDbDataAdapter(); 9. OleDbCommandBuilder builder = new OleDbCommandBuilder(daDest); 10. 11. daDest.AcceptChangesDuringFill = false; 12. daDest.SelectCommand = new OleDbCommand(queryString2, dbConnDest); 13. daDest.InsertCommand = builder.GetInsertCommand(); 14. daDest.UpdateCommand = builder.GetUpdateCommand(); 15. daDest.TableMappings.Add("Table", destTableName); 16. 17. daDest.Fill(dsDest); 18. DataTable dtFolder1 = ds.Tables[sourceTableName].Copy(); 19. dtFolder1.TableName = destTableName; 20. dsDest.Merge(dtFolder1); 21. 22. int updateCount = daDest.Update(dsDest, destTableName); 23. 24. return updateCount; 25. } How It Works
One of the most important first steps is actually in the function that retrieves my original DataSet. You need to set the following DataAdapter property:
daSource.AcceptChangesDuringFill = false; This instructs the DataAdapter not to automatically perform an AcceptChanges command after the DataSet has been filled. This is very important because we need the RowState for each of the rows in the DataTable to remain as they were.
On Line 18, you will notice that we are creating a new table called dtFolder1 and populating the table's Schema and Data by performing a Copy command. On Line 20, we are performing a Merge command to merge the Destination DataTable data with that of the Source DataTable. If we had not set the AcceptChangesDuringFill to false, the RowState for the copied records would have been set to Unchanged and we needed each RowState to be set to Added.
So why is this so important? Well, mostly because the Update command we perform on Line 22 looks at the RowState for each row in the DataTable and only updates the physical database with rows that are in some way different or changed. This was what was causing much of my waste of time: the database wasn't getting updated, and I found no indication as to why this was happening.
Moving Data Alternative Method
A secondary method for moving data between DataTables in separate DataSets is to do it Row by Row, as in the following example:
1. DataTable dtFolder1 = ds.Tables[sourceTableName].Clone(); 2. dtFolder1.TableName = destTableName; 3. 4. foreach (DataRow oRow in ds.Tables[sourceTableName].Rows) 5. { 6. DataRow newRow = dtFolder1.NewRow(); 7. newRow.ItemArray = oRow.ItemArray; 8. dtFolder1.Rows.Add(newRow); 9. } 10. 11. dsDest.Merge(dtFolder1); 12. In this example we're using the Clone command to clone the Schema from the Source DataTable and moving the data, one row at a time, to the Destination DataTable. Adding rows to the Destination DataTable automatically sets the RowState to Added so the Update command will treat them as new rows and put them into the database.
Other Notes on the Code
I pass in a reference to my Source DataSet when invoking the function.
Line 15 create a table name mapping between the default table, called "Table" to the name of my destination table. In this application, my source and destination table names are different, so I must rename the table after it is copied, which I do on Line 19. If your table names are the same, you may skip this step.
Lines 13 and 14 will instruct the Adapter to dynamically create Insert and Update commands required for this DataTable.
Note: You must have a Primary Key defined for your database table. The Primary Key is used by the DataAdapter to locate records for update and/or insert. If you don't have a Primary Key, you will get an error message stating the case and aborting your Update operation.
Final Note
I'm writing with VS 2003 and .NET 1.1 so I'm not sure if any of this has been corrected or changed in .NET 2.0.
Development 1,943 views -
I've added article ratings to my blog
Greetings Everyone,
In order to get a better understanding of what people like to read and find useful, I have added a ratings control at the end of each blog article that looks something like this:
It uses a 5-star rating and all you do to rate an article is just click on the star that represents your choice.
Note: You may only vote once per article.
After you have voted, you will see your vote like this:
Again, I will use this information ( and votes from any Polls that I may have running ) to help determine what people are interested in so that I can hopefully tailor my blog content to meet those needs.
So, if it's not too much trouble, I would greatly appreciate it if you would vote on each article that you read.
Thanks and have a great week.
Mitch
Misc 1,164 views -
Live from Arkansas: Do cows boat?
Before I left Arkansas Saturday morning, me and my Dad went out to feed the cows. He has a couple of small ponds in the pasture and on one of those, he has a Jon Boat.
As we drove down toward the pond, we found three calves standing around the boat. Two of them had their front legs inside the boat.
I still don't know what the heck is going on. Do cows yacht around the pond while people aren't around? Do they fish? Do they drink beer and fish?
Who knows…
Meanderings 1,190 views






