Get entity record values from Audit Details Response - dynamics-crm-2011

Auditing of an entity is enabled,I want the entity record after deletion.So
I was trying to get that from audit entity records,like this:
RetrieveAuditDetailsRequest request = new RetrieveAuditDetailsRequest();
request.AuditId = _selectedId;
RetrieveAuditDetailsResponse response = (RetrieveAuditDetailsponse)_orgService.Execute(request);
EntityReference ObjectId = (EntityReference)response.AuditDetail.AuditRecord.Attributes["objectid"];
string ObjectName = ObjectId.LogicalName;
Guid Id = ObjectId.Id;
ColumnSet col = new ColumnSet(true);
Entity ent = _orgService.Retrieve(ObjectName,Id,col);
Its throwing an error "Expected non empty Guid".
FYI, I want this record values because I want to restore/recover record by creating it again.
Please help whats wrong with it??

You are attempting to retrieve the deleted record with this code:
string ObjectName = ObjectId.LogicalName;
Guid Id = ObjectId.Id;
ColumnSet col = new ColumnSet(true);
Entity ent = _orgService.Retrieve(ObjectName,Id,col);
This will fail with the error you are getting because no such record exists (it is deleted.) Unlike CRM 4 and earlier there are no soft deletes in 2011, once deleted it is gone from the database.
Replace it with the following code:
RetrieveRecordChangeHistoryRequest retrieveRequest = new RetrieveRecordChangeHistoryRequest();
changeRequest.Target = new EntityReference(ObjectName, Id);
RetrieveRecordChangeHistoryResponse response =
(RetrieveRecordChangeHistoryResponse)_orgService.Execute(retrieveRequest);
if (response.AuditDetailCollection != null)
{
var auditDetails = response.AuditDetailCollection;
// Do work
}
You then enumerate through the auditDetails to get the correct attributes.
You can find more at http://blogs.msdn.com/b/crm/archive/2011/05/23/recover-your-deleted-crm-data-and-recreate-them-using-crm-api.aspx.

The "Expected non empty Guid" error is thrown whenever you try to retrieve something with an empty GUID (Guid.Empty, 00000000-0000-0000-0000-000000000000). I'm guessing your _selectedId is not set to an actual GUID. Maybe you're setting it from a Nullable GUID and you are calling ValueOrDefault(), which is resulting in it getting set to the empty Guid, and failing in your Request?

Related

ServiceStack: Update<T>(...) produces 'duplicate entry'

I have tried reading the docs, but I don't get why the Update method produces a "Duplicate entry" MySQL error.
The docs says
In its most simple form, updating any model without any filters will update every field, except the Id which is used to filter the update to this specific record:
So I try it, and pass in an object, like below. A row with id 2 already exists.
using (var _db = _dbFactory.Open())
{
Customer coreObject = new Customer(...);
coreObject.Id = 2;
coreObject.ObjectName = "a changed value";
_db.Update<Customer>(coreObject); // <-- error "duplicate entry"
}
Yes, there are options using .Save and such, but what am I missing with the .Update? As I read it, it should use its Id property to update the row in the db, not insert a new row?
The issue with this method is that you're updating a generic object T but your Update API says to update the Concrete Customer type:
public void MyTestMethod<T>(T coreObject) where T : CoreObject
{
long id = 0;
using (var _db = _dbFactory.Open())
{
id = _db.Insert<T>(coreObject, selectIdentity: true);
if (DateTime.Now.Ticks == 0)
{
coreObject.Id = (uint)id;
_db.Delete(coreObject);
}
if (DateTime.Now.Ticks == 0)
{
_db.DeleteById<Customer>(id);
}
if (DateTime.Now.Ticks == 0)
{
coreObject.Id = (uint)id;
coreObject.ObjectName = "a changed value";
_db.Update<Customer>(coreObject);
}
}
}
Which OrmLite assumes that you're using a different/anonymous object to update the customer table, similar to:
db.Update<Customer>(new { Id = id, ObjectName = "a changed value", ... });
Which as it doesn't have a WHERE filter will attempt to update all rows with the same primary key.
What you instead want is to update the same entity, either passing in the Generic Type T or have it inferred by not passing in any type, e.g:
_db.Update<T>(coreObject);
_db.Update(coreObject);
Which will use OrmLite's behavior of updating entity by updating each field except for Primary Keys which it instead used in the WHERE expression to limit the update to only update that entity.
New Behavior in v5.1.1
To prevent accidental misuse like this I've added an Update API overload in this commit which will use the Primary Key as a filter when using an anonymous object to update an entity, so your previous usage:
_db.Update<Customer>(coreObject);
Will add the Primary Key to the WHERE filter instead of including it in the SET list. This change is available from v5.1.1 that's now available on MyGet.

Exchange Service Finditems giving 407 error

we need to search email from outlook.com and to achieve this we are using Exchange Web Service (EWS) but getting 407 error a the time of calling FindItem method of service.
Here is the code which we are working on -
List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Subject, "Test"));
//searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Body, "homecoming"));
SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());
ItemView view = new ItemView(50);
// Identify the properties to return in the result set and the additional properties that are returned for each item.
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, ItemSchema.DateTimeReceived);
//Order the search results by the DateTimeReceived property. The sort direction is in descending order.
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
//Set the manner by which the search filter traverses the target folder. In the following example, the search filter performs a shallow traversal. Shallow is the default option; other traversal options are Associated and SoftDeleted.
view.Traversal = ItemTraversal.Shallow;
string userEmailAddress = "username#outlook.com";
string userPassword = "OutlookPassword";
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
service.Credentials = new WebCredentials(userEmailAddress, userPassword);
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilter, view);
Getting error at last line of code.
Can you please guide what need to be correct to resolve it?
Thank You!

Linq queries and optionSet labels, missing formatted value

I'm doin a simple query linq to retrieve a label from an optionSet. Looks like the formatted value for the option set is missing. Someone knows why is not getting generated?
Best Regards
Sorry for the unclear post. I discovered the problem, and the reason of the missing key as formattedvalue.
The issue is with the way you retrieve the property. With this query:
var invoiceDetails = from d in xrmService.InvoiceSet
where d.InvoiceId.Value.Equals(invId)
select new
{
name = d.Name,
paymenttermscode = d.PaymentTermsCode
}
I was retrieving the correct int value for the option set, but what i needed was only the text. I changed the query this way:
var invoiceDetails = from d in xrmService.InvoiceSet
where d.InvoiceId.Value.Equals(invId)
select new
{
name = d.Name,
paymenttermscode = d.FormattedValues["paymenttermscode"]
}
In this case I had an error stating that the key was not present. After many attempts, i tried to pass both the key value and the option set text, and that attempt worked just fine.
var invoiceDetails = from d in xrmService.InvoiceSet
where d.InvoiceId.Value.Equals(invId)
select new
{
name = d.Name,
paymenttermscode = d.PaymentTermsCode,
paymenttermscodeValue = d.FormattedValues["paymenttermscode"]
}
My guess is that to retrieve the correct text associated to that option set, in that specific entity, you need to retrieve the int value too.
I hope this will be helpful.
Best Regards
You're question is rather confusing for a couple reasons. I'm going to assume that what you mean when you say you're trying to "retrieve a label from an OptionSet" is that you're attempting to get the Text Value of a particular OptionSetValue and you're not querying the OptionSetMetadata directly to retrieve the actual LocalizedLabels text value. I'm also assuming "formatted value for the option set is missing" is referring to the FormattedValues collection. If these assumptions are correct, I refer you to this: CRM 2011 - Retrieving FormattedValues from joined entity
The option set metadata has to be queried.
Here is an extension method that I wrote:
public static class OrganizationServiceHelper
{
public static string GetOptionSetLabel(this IOrganizationService service, string optionSetName, int optionSetValue)
{
RetrieveOptionSetRequest retrieve = new RetrieveOptionSetRequest
{
Name = optionSetName
};
try
{
RetrieveOptionSetResponse response = (RetrieveOptionSetResponse)service.Execute(retrieve);
OptionSetMetadata metaData = (OptionSetMetadata)response.OptionSetMetadata;
return metaData.Options
.Where(o => o.Value == optionSetValue)
.Select(o => o.Label.UserLocalizedLabel.Label)
.FirstOrDefault();
}
catch { }
return null;
}
}
RetrieveOptionSetRequest and RetrieveOptionSetResponse are on Microsoft.Xrm.Sdk.Messages.
Call it like this:
string label = service.GetOptionSetLabel("wim_continent", 102730000);
If you are going to be querying the same option set multiple times, I recommend that you write a method that returns the OptionSetMetadata instead of the label; then query the OptionSetMetadata locally. Calling the above extension method multiple times will result in the same query being executed over and over.

How to get id of saved entity

Dynamics CRM 2011 on premise
I can barely believe I can't find this out by Googling. MSDN is useless.
Here is some C# from a plugin:
integ_creditpayment creditpayment = new integ_creditpayment();
creditpayment.integ_Amount = totalPay;
//set more properties
context.AddObject(creditpayment);
context.SaveChanges();
Now I want to get the value of the id field in integ_creditpayment.
Can I get this immediately from creditpayment.id? (As in, does context.SaveChanges() cause the creditpayment variable to be updated with the new id?)
I'm assuming your real code is more complicated, but there is no need to use the context in your example code:
integ_creditpayment creditpayment = new integ_creditpayment();
creditpayment.integ_Amount = totalPay;
//set more properties
creditpayment.Id = service.Create(creditpayment);
You can also use a type initializer and get rid of your object all together if you'd like:
Guid id = service.Create(new integ_creditpayment
{
integ_Amount = totalPay;
});
service in this case is of type IOrganizationService
After the SaveChanges() you can get the record id with:
Guid justCreatedId = creditpayment.Id;

Windows Azure: "An item with the same key has already been added." exception thrown on Select

I'm getting a strange error while trying to select a row from a table under Windows Azure Table Storage. The exception "An item with the same key has already been added." is being thrown even though I'm not inserting anything. The query that is causing the problem is as follows:
var ids = new HashSet<string>() { id };
var fields = new HashSet<string> {"#all"};
using (var db = new AzureDbFetcher())
{
var result = db.GetPeople(ids, fields, null);
}
public Dictionary<string, Person> GetPeople(HashSet<String> ids, HashSet<String> fields, CollectionOptions options)
{
var result = new Dictionary<string, Person>();
foreach (var id in ids)
{
var p = db.persons.Where(x => x.RowKey == id).SingleOrDefault();
if (p == null)
{
continue;
}
// do something with result
}
}
As you can see, there's only 1 id and the error is thrown right at the top of the loop and nothing is being modified.
However, I'm using "" as the Partition Key for this particular row. What gives?
You probably added an object with the same row key (and no partition key) to your DataServiceContext before performing this query. Then you're retrieving the conflicting object from the data store, and it can't be added to the context because of the collision.
The context tracks all object retrieved from the Tables. Since entities are uniquely identified by their partitionKey/rowKey combination, a context, like the tables, cannot contain duplicate partitionkey/rowkey combinations.
Possible causes of such a collison are:
Retrieving an entity, modifying it, and then retrieving it again using the same context.
Adding an entity to the context, and then retrieving one with the same keys.
In both cases, the context the encounters it's already tracking a different object which does however have the same keys. This is not something the context can sort out by itself, hence the exception.
Hope this helps. If you could give a little more information, that would be helpful.

Resources