microsoft dynamics crm - SQL changes - dynamics-crm-2011

Hi I'm facing a task that requires me (or not?) to do some small changes directly on the CRM SQL DB.
Situation:
1) there was a N:1 relation between two entities that was changed to N:N.
2) For each entities I need to move related stuff from previous relation to new one.
For active entities it was no problem cause customer didn't care about changing fields "ModifiedOn", "ModifiedBy" and "ClosedOn" but for inactive (an incident that is closed for example) he'd like to migrate the related entities, but not to change these three fields. Because all those incidents are closed/inactive I cannot just call "AssociateRequest" I need to re-open case, associate, close it again. this of course will change these fields.
Is there any way to do this via the API and not directly on SQL? If not - could it be a problem?

If you already have the mechanism to change the Relationship and just need to modify the records CreatedOn, CreatedBy, ModifiedOn, and ModifiedBy...You should be able to do this using late bound code:
Entity YourTargetEntity= new Entity("YourTargetEntity");
YourTargetEntity["createdon"] = new DateTime(2015,01,01); // or whatever the date you want
YourTargetEntity["overriddencreatedon"] = new DateTime(2015,01,01); // or whatever the date you want
YourTargetEntity["createdby"] = new EntityReference("systemuser", new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
TargetEntity["modifiedby"] = new EntityReference("systemuser", new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
TargetEntity["modifiedon"] = new DateTime(2015,01,01); // or whatever the date you want
_service.Update(YourTargetEntity);
Hope that helps.

Related

How to update records "unrelated" to current graph?

I am not sure if i have just forgotten how to go about this or whether i havent had to do it before....
I have a new custom page with new tables and graph associated with it. It works fine for maintaining this custom data. I have an action that needs to update a custom field in INItemLotSerial (note this does not have a graph associated with it). Normally, i have created an instance of the corresponding graph and done updates using that instance.
I just need to do the equivalent of update INItemLotSerial set usr1 = 'test' where InventoryID = x and LotSerialNbr = y
I am unsure how to approach this? i was thinking i could select the record into an instance of the DAC and update the values, but i do not know how to commit that back to the DB.
you need view. Let's say you made view like this:
public PXSelect<PMTask> PMTasksSelect;
you read your object in some way
PMTask pm = PMTasksSelect.Select(Base).FirstOrDefault();
Inform cache of Acumatica that you changed object:
PMTasksSelect.Cache.SetValueExt(pm, "RateTableID", "A");
PMTasksSelect.Cache.SetStatus(task2, PXEntryStatus.Modified);
PMTasksSelect.Cache.IsDirty = true;
Finally you can persist your changes to db:
PMTasksSelect.Cache.Update(taskExt);
You need a view related to the DAC you want to update. So in this case, you can define a view for the DAC like
public PXSelect<INItemLotSerial, Where<INItemLotSerial.inventoryID, Equal<Current<YourField>>,
And<INItemLotSerial.lotSerialNbr, Equal<Current<YourField>>>>> LotSerialInfo;
So this view will cache the record you want to update. Now you can update the record anytime like
INItemLotSerial rec = LotSerialInfo.Current as INItemLotSerial;
//Get extension if you want
recExt.YourExtField = "something";
LotSerialInfo.Update(rec);
The persist of your graph will save the information you Inserted/Updated/Deleted.
Hope It gives you the idea and helps. :)

How to preform a relative complement query in CRM?

Background (ie what the heck is a relative complement?)
Relative Complement
What I'm trying to do
Let's say I've got a custom Vehicle entity that has a VehicleType option set that is either "Car", or "Truck". There is a 1 to many relationship between Contact and Vehicle (ie. ContactId is on the vehicle entity). How do I write an XRM query (Linq To CRM, QueryExpression, fetch Xml, whatever) that returns the contacts with only cars?
Option 1:
I’d prefer a modification of the proposal that AdamV makes above. I can’t think of a way that you’d get this particular query answered using Linq to CRM, Query Expressions, FetchXML alone. Daryl doesn’t offer what the client is, but I would suppose if Linq and Query Expressions were acceptable offerings, .NET is on the table. Creating aggregate fields containing the count of the related entity on the parent entity (contact in this case) offers more than the Boolean option. If the query requirements ever changed to a threshold (more than X cars, less than Y trucks, between X and Y total vehicles) the Boolean options fails to deliver. The client in this question isn’t known, but I can’t think of many (any?) cases where pulling all the records to the client on a set of 500K+ rows is more efficient than a the SQL query that CRM would make on your behalf against several integer fields with range clauses.
Upside:
Maintains client purity in Query approach
Simple client query
Probably as performant as possible
Downside:
Setups for Aggregate fields
Workflow or plugin to manage the increment and decrement of the aggregate fields
SQL Script for initial load of the aggregates.
Risk that aggregate fields get out of sync (workflow or plugin fails)
Option 2:
If purity within the client isn’t essential, and .NET is on the table – skip the aggregate fields and the setup and just run SQL against the Views. If you don’t want to work with the ADO.NET, a thin ORM like Dapper, Massive, or PetaPOCO can still give you an object model. As Andreas offers in his comment on the OP’s first answer, it seems like something fairly trivial to do in SQL.
Sketching something from top of mind:
SELECT c.*
FROM Contact
WHERE C.Contactid in (
Select contactid
FROM Vehicle v
group by v.contactid , v.type
having v.type = ‘Car’ and count(contactid) > 1
)
AND NOT IN (
Select contactid
FROM Vehicle v
group by v.contactid , v.type
having v.type <> ‘Car’ and count(contactid) > 1
)
Upside:
Much less work
CRM Entities get left alone
Downside:
Depending on the client and/or the application mixing DataAccess methods is a bit kludgy.
Likely less performant than Option 1
Option 3:
Mix and Match: Take the aggregate fields from Option 1. But update them using a scheduled SQL job (or something similar) with a query similar to the initial load job you’d need to write in Option 1
Upside:
Takes most of the work and risk out of Option 1
Keeps all of the performance of Option 1
Downside:
Some will see this as an unsupported feature.
In order to order to perform a true Relative Complement Query you need to be able to perform a subquery.
Your query would basically say give me all the contacts with cars, and then, within those results, remove any contacts that have a vehicle that isn't a car. This is what the SQL in #JasonKoopmans answer does. Unfortunetly, CRM does not support SubQueries.
Therefore, the only way to achieve this is to either perform the sub query on the client side, as I resorted to doing, or storing the results of what would be the subquery in a manner that can be accessed through the main query (ie storing counts on the contact entity).
You could theoretically do this "on the fly" by making a SubQueryResult entity that stores a ContactId, and SubQueryId. You'd first pull back the contacts that have at least 1 car, and create a SubQueryResult record for each record, with it's contactId, and a single SubQueryId that is generated client side to tie them all together.
Then you'd do another query that says give me all the contacts that are in this SubQueryResult with this SubQueryId, that do not have any vehicles that aren't cars.
I could only assume that this wouldn't be any more efficient than performing the two separate queries and performing the filter client side. Although with the new ExecuteMultipleRequests in the new CRM release, it may be close.
I have resorted to pulling back all of my records in CRM, and performing the check on the client side since CRM 2011 doesn't support this via Query Expressions.
You could write two Fetch XML statements, one to return all contacts and the count of their vehicles, and another to return all contacts and the count of their cars, then compare the list on the client side. But once again, you're having to return every contact and filter it client side.
It's not tested but how about this query expression? I'm linking in the Vehicle entity as an inner join, requiring that it's a Car. I'm assuming that the field VehicleType is a String because I'm a bit lazy and don't want to test it (I'm typing this hardcore style, no compilation - pure brain work).
Optionally, you might want to add a Criteria section as well to control which of the Contact instances that actually get retrieved. Do tell how it went!
Sorry for the verbosity. I know you like it short. My brains work better when circumlocutory.
new QueryExpression
{
EntityName = "contact",
ColumnSet = new ColumnSet("fullname"),
LinkEntities =
{
new LinkEntity
{
JoinOperator = JoinOperator.Inner,
LinkFromEntityName = "contact",
LinkFromAttributeName = "contactid",
LinkToEntityName = "vehicle",
LinkToAttributeName = "contactid",
Columns = new ColumnSet("vehicletype"),
EntityAlias = "Vroom",
//LinkCriteria = { Conditions =
//{
// new ConditionExpression(
// "vehicletype", ConditionOperator.Equal, "car")
//} }
LinkCriteria = { Conditions =
{
new ConditionExpression(
"vehicletype", ConditionOperator.NotEqual, "truck")
} }
}
}
};
EDIT:
I've talk to my MVP Gustaf Westerlund and he's suggested the following work-around. Let me stress that it's not an answer to your original question. It's just a way to solve it. And it's cumbersome. :)
So, the hint is to add a flag in the Contact or Person entity. Then, every time you create a new instance of Vehicle, you need to fire a message and using a plugin, update the information on the first about the creation of the latter.
This has several drawbacks.
It requires us to do stuff.
It's not the straight-forward do-this-and-that type of approach.
Maintenance is higher for every new type of Vehicle one adds.
Buggibility is elevated since there are many cases to regard (what happens to the flagification when a Vehicle instance is reasigned, deleted etc.).
So, my answer to your question is changed to: "can't be done". This remains effective until (gladly) proven wrong by presented alternative solution. Duck!
Personally, I'd fetch (almost) everything and unleash the hounds of LINQ onto it. But I'd do that without smiling nor proud. :)

CouchDB - Auto-increment

In a non-replicate scenario (or one where we have one write master only), would the following work as quick way to give a doc an auto-increment id to small internal customer datbase.
On inserting a new customer query http://couhdb/mydb to get the metadata
Then add doc_count + doc_deleted_count = autoIncId
Set a property on the doc as .oldDbCompatIdThatClientIsUsedTo = auotIncId
This would mean serialize/sync the process of getting the db metadata and writting the doc but thats not a problem given 20 customers added a day etc..
I can think of a couple of ways of doing this:
Create a view that returns max(id) and just assign max(id) + 1 to the new item (there's some chance of collision here though)
Store another document in the database that isn't a normal record but just contains the sequence value. When you want to do a new insert fetch the current value from this doc, add one, save it back to the doc and then if none of that failed use that id for the new record

Can SubSonic's SimpleRepository enlist in a transaction for two different object types?

I've been exploring Sub Sonic 3's SimpleRepository and have been pretty happy with it but have a question regarding transactions. I am aware that using methods like 'AddMany' and 'DeleteMany' will automatically perform all of those operations within a single transaction, but was wondering if it's possible to force the SimpleRepository to perform the add or update of two different object types within the same transaction. For example, let's say I have the notion of two different but related entities in my application: a User and a Profile. Every user has to have a Profile and every Profile belongs to one and only one user. When a new user registers with my application I want them to provide the basic user information (credentials, name, e-mail) but also want some additional "profile" information (about me, gender, zip code, etc.)
I'd like to be able to perform the add of the User and the Profile object within a single transaction, but since it requires two distinct calls to the 'Add' method with different type parameters I'm not sure how to make this work.
You can do this using a transaction as follows:
using (TransactionScope transactionScope = new TransactionScope())
{
using (SharedDbConnectionScope connectionScope = new SharedDbConnectionScope())
{
// Add your user
// Add your profile
transactionScope.Complete();
}
}
adam - i think the code above is correct but is actually the wrong way around, it should be:
using (SharedDbConnectionScope connectionScope = new SharedDbConnectionScope())
{
using (TransactionScope transactionScope = new TransactionScope())
{
// Add your user
// Add your profile
transactionScope.Complete();
}
}
cheers
jimi

Sharepoint: SQL to find all documents created/edited by a user

I am looking for a query that will work on Sharepoint 2003 to show me all the documents created/touched by a given userID.
I have found tables with the documents (Docs) and tables for users (UserInfo, UserData)
but the relationship between seems a bit odd - there are 99,000 records in our userdata table, and 12,000 records in userinfo - we have 400 users!
I suppose I was expecting a simple 1 to many relationship with a user table having 400 records and joining that to the documents table, but I see thats not the case.
Any help would be appreciated.
Edit:
Thanks Bjorn,
I have translated that query back to the Sharepoint 2003 structure:
select
d.* from
userinfo u join userdata d
on u.tp_siteid = d.tp_siteid
and
u.tp_id = d.tp_author
where
u.tp_login = 'userid'
and
d.tp_iscurrent = 1
This gets me a list of siteid/listid/tp_id's I'll have to see if I can trace those back to a filename / path.
All: any additional help is still appreciated!
I've never looked at the database in SharePoint 2003, but in 2007 UserInfo is connected to Sites, which means that every user has a row in UserInfo for each site collection (or the equivalent 2003 concept). So to identify what a user does you need both the site id and the user's id within that site. In 2007, I would begin with something like this:
select d.* from userinfo u
join alluserdata d on u.tp_siteid = d.tp_siteid
and u.tp_id = d.tp_author
where u.tp_login = '[username]'
and d.tp_iscurrentversion = 1
Update: As others write here, it is not recommended to go directly into the SharePoint database, but I would say use your head and be careful. Updates are an all-caps no-no, but selects depends on the context.
DO NOT QUERY THE SHAREPOINT DATABASE DIRECTLY!
I wonder if I made that clear enough? :)
You really need to look at the object model available in C#, you will need to get an SPSite instance for a SiteCollection, and then iterate over the SPList instances that belong to the SPSite and the SPWeb objects.
Once you have the SPList object, you will need to call GetListItems using a query that filters for the user you want.
That is the supported way of doing what you want.
You should never go to the database directly as SharePoint isn't designed for that at all and there is no guarantee (actually, there's a specific warning) that the structure of the database will be the same between versions and upgrades, and additionally when content is spread over several content databases in a farm there is no guarantee that a query that runs on one content database will do what you expect on another content database.
When you look at the object model for iteration, also note that you will need to dispose() the SPSite and SPWeb objects that you create.
Oh, and yes you may have 400 users, but I would bet that you have 30 sites. The information is repeated in the database per site... 30 x 400 = 12,000 entries in the database.
If you are going to use that query in Sharepoint you should know that creating views on the content database or quering directly against the database seems to be a big No-No. A workaround could be some custom code that iterates through the object model and writes the results to your own database. This could either be timer based or based on an eventtrigger.
You really shouldn't be doing SELECTs with Locks either i.e. adding WITH (NOLOCK) to your queries. Some parts of the system are very timeout sensitive and if you start introducing locks that the system wasn't expecting you can see the system freak out.
But really, you should be doing this via the object model. Mess around with something like IronPython and experimentations with the OM are almost downright pleasant.

Resources