Dynamics CRM- update record of contact entity - dynamics-crm-2013

I have created contact record using ASP.NET. Now I need to Check if the contact record exists. If exists, update the same record. Through advance find have downloaded FetchXML and added to my FetchXML variable. Please suggest the logic. Below is my code.
// Establish a connection to crm and get the connection proxy
string connectionString = "xyz; Username= xyz ;Password=xyz";
CrmConnection connect = CrmConnection.Parse(connectionString);
OrganizationService service;
using (service = new OrganizationService(connect))
{
WhoAmIRequest request = new WhoAmIRequest();
Guid userId = ((WhoAmIResponse)service.Execute(request)).UserId;
ContactDetails contact = new ContactDetails();
//Check if the contact record exists . If exists , update the same record.
//Fecthxml query
string fetchXml = #" <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='contact'>
<attribute name='fullname' />
<attribute name='parentcustomerid' />
<attribute name='telephone1' />
<attribute name='emailaddress1' />
<attribute name='contactid' />
<order attribute='fullname' descending='false' />
<filter type='and'>
<condition attribute= 'mobilephone' operator='not-null' />
</filter>
</entity>
</fetch>" ;
FetchExpression query = new FetchExpression(fetchXml);
EntityCollection results = service.RetrieveMultiple(query);
if (results.Entities.Count > 0)
{
Entity contactRecord = results[0];
contactRecord["firstname"] = contactInfo.FirstName;
contactRecord["lastname"] = contactInfo.LastName;
contactRecord["emailaddress1"] = contactInfo.EmailId;
contactRecord["mobilephone"] = contactInfo.MobilePhone;
contactRecord["address1_line1"] = contactInfo.Street1;
contactRecord["address1_line2"] = contactInfo.Street2;
contactRecord["address1_line3"] = contactInfo.Street3;
contactRecord["address1_city"] = contactInfo.City;
service.Update(contactRecord);
}
//Else, Create the contact record
else
{
Entity entity = new Entity();
entity.LogicalName = "contact";
entity["firstname"] = contactInfo.FirstName;
entity["lastname"] = contactInfo.LastName;
entity["emailaddress1"] = contactInfo.EmailId;
entity["mobilephone"] = contactInfo.MobilePhone;
entity["address1_line1"] = contactInfo.Street1;
entity["address1_line2"] = contactInfo.Street2;
entity["address1_line3"] = contactInfo.Street3;
entity["address1_city"] = contactInfo.City;
entity["address1_stateorprovince"] = contactInfo.State;
entity["address1_country"] = contactInfo.Country;
entity["spousesname"] = contactInfo.SpouseName;
entity["birthdate"] = contactInfo.Birthday;
entity["anniversary"] = contactInfo.Anniversary;
//Create entity gender with option value
if (contactInfo.Gender == "Male")
{
entity["gendercode"] = new OptionSetValue(1);
}
else
{
entity["gendercode"] = new OptionSetValue(2);
}
//entity["familystatuscode"] = contactInfo.MaritalStatus;
if (contactInfo.MaritalStatus == "Single")
{
entity["familystatuscode"] = new OptionSetValue(1);
}
else
{
entity["familystatuscode"] = new OptionSetValue(2);
}
service.Create(entity);
}
}
// Create the entity

your logic seems ok, with the exception of the FectchXML query. The way you have your code, you will always end up updating the first record retrieved that has its mobilephone field filled. That does not seem a good way to check if a contact already exists.
I suggest you to change the filter of your fetch. In your filter condition you have to use an attribute that represents uniqueness for all contacts.
Apart of this your code looks ok.

Like nunoalmeieda says, you need to have a better way to ascertain if the Contact already exists. A common way of identifying if the Contact already exists would be to check if the email address already exists as it is very unlikely that two people will have the same email address.
I have updated your basic code to show how it is done with FetchXML.
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<entity name="contact">
<attribute name='fullname' />
<attribute name='parentcustomerid' />
<attribute name='telephone1' />
<attribute name='emailaddress1' />
<attribute name='contactid' />
<order attribute="fullname" descending="false" />
<filter type="and">
<condition attribute="emailaddress1" operator="eq" value=contactInfo.EmailId />
</filter>
</entity>
</fetch>
The logic here is that I am checking if the value of emailaddress1 (field in the contact entity of CRM) is equal to the value of your contactInfo.EmailId. I am assuming that contactInfo is the record that you get from ASP.NET.
The rest of your code is fine (I have formatted it a bit to make the question more readable).

Related

Sitecore 7 Index treelist lucene

I have Sitecore items with a treelist property referring to other items (with different a template).
My goal is to find item A that contains item B in the treelist property using the ContentSearch api (lucene).
I've added the treelist property to my index:
<indexConfigurations>
<defaultLuceneIndexConfiguration type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider">
<fieldMap type="Sitecore.ContentSearch.FieldMap, Sitecore.ContentSearch">
<fieldNames hint="raw:AddFieldByFieldName">
<field patch:before="field[0]" fieldName="TreelistProperty" storageType="YES" indexType="UNTOKENIZED" vectorType="NO" boost="1f" type="System.String"
settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
<analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
</field>
</fieldNames>
</fieldMap>
</defaultLuceneIndexConfiguration>
</indexConfigurations>
I would expect that lucene stores the treelist property as a concatenation of guids.
Assuming this is correct and my index is populated my query looks like this:
master = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = master.CreateSearchContext())
{
var results = context.GetQueryable<SearchResultItem>()
.Where(x => x["TreelistProperty"].Contains("{456-41414-my-guid-here-1516}"))
.GetResults();
var hits = results.Hits.ToArray();
}
This returns nothing. Where did it go wrong?
You should normalize your guid, like this:
var master = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = master.CreateSearchContext())
{
Sitecore.Data.ID myId = ID.Parse("{456-41414-my-guid-here-1516}");
string normalizedID = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(myId );
var results = context.GetQueryable<SearchResultItem>()
.Where(x => x["TreelistProperty"].Contains(normalizedID))
.GetResults();
var hits = results.Hits.ToArray();
}
I think there is a typo in your index configuration, can you try
indexType="UN_TOKENIZED"
You can also investigate what values are in your lucene indexes using luke
http://www.sitecore.net/en-gb/learn/blogs/technical-blogs/getting-to-know-sitecore/posts/2013/06/using-luke-to-understand-sitecore-7-search.aspx
I think the guid values are stored without the braces and dashes by default. Try converting to ToShortId() before the comparison.

Sorting on date field with Sitecore 7 ContentSearch

I'm trying to add a field sort to a date field in a ContentSearch query. I'm able to filter on the index field properly so I'm assuming the field is getting populated with values properly, however, results are not being sorted properly. Any thoughts? Here's the code I'm using to do query:
public static IEnumerable<Episode> GetPastEpisodes(Show show, bool includeMostRecent = false, int count = 0)
{
IEnumerable<Episode> pastEpisodes;
using (var context = _index.CreateSearchContext())
{
// querying against lucene index
pastEpisodes = context.GetQueryable<Episode>().Where(GetPastAirDatePredicate(show));
if(!includeMostRecent)
{
pastEpisodes = pastEpisodes.Where(item => item.Id != GetMostRecentEpisode(show).Id);
}
pastEpisodes = pastEpisodes.OrderByDescending(ep => ep.Latest_Air_Date);
if (count > 0)
{
pastEpisodes = pastEpisodes.Take(count);
}
pastEpisodes = pastEpisodes.ToList();
// map the lucene documents to Sitecore items using the database
foreach (var episode in pastEpisodes)
{
_database.Map(episode);
}
}
return pastEpisodes;
}
private static Expression<Func<Episode,bool>> GetPastAirDatePredicate(Show show)
{
var templatePredicate = PredicateBuilder.Create<Episode>(item => item.TemplateId == IEpisodeConstants.TemplateId);
var showPathPredicate = PredicateBuilder.Create<Episode>(item => item.FullPath.StartsWith(show.FullPath));
var airDatePredicate = PredicateBuilder.Create<Episode>(item => item.Latest_Air_Date < DateTime.Now.Date.AddDays(1));
var fullPredicate = PredicateBuilder.Create<Episode>(templatePredicate).And(showPathPredicate).And(airDatePredicate);
return fullPredicate;
}
The field is stored and untokenized and using the LowerCaseKeywordAnalyzer.
<field fieldName="latest_air_date" storageType="YES" indexType="UN_TOKENIZED" vectorType="NO" boost="1f" type="System.DateTime" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
<analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider"/>
</field>
Episode class has IndexField attribute set:
[IndexField("latest_air_date")]
public virtual DateTime Latest_Air_Date {get; set; }
Kyle,
As far as I can tell everything looks correct with your configuration and code. I mocked out something very similar in a vanilla Sitecore 7.2 instance and Dates sorted without issue.
One thing to note though, and this might be what is giving you some issues, is that Sitecore's FieldReader for DateTime only store the date portion of the DateTime. If you are expecting to be able to sort by true DateTime you will need to add a custom FieldReader or some computed fields.
See this blog that discusses the issue and explains the process to swap out a custom field reader: http://reasoncodeexample.com/2014/01/30/indexing-datetime-fields-sitecore-7-content-search/
I would also suggest looking at the index with Luke to verify what data is actually in the index. https://code.google.com/p/luke/
And finally you may want to enable Search debugging in Sitecore to see exactly how Sitecore is executing the query in Lucene.
Sitecore.ContentSearch.config:
<setting name="ContentSearch.EnableSearchDebug" value="true" />

Authoring XACML 3.0 obligations with the ALFA plugin for Eclipse

I have an XACML request with two (resource:type) attributes and one (resource:id) attribute:
<Request xmlns="urn:oasis:names:tc:xacml:2.0:context:schema:os" >
<Resource>
<Attribute AttributeId="resource:type" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>status</AttributeValue>
</Attribute>
<Attribute AttributeId="resource:type" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>pressure</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>status:of:nariman</AttributeValue>
</Attribute>
</Resource>
<Subject>
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>1111</AttributeValue>
</Attribute>
</Subject>
<Action>
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id">
<AttributeValue>view</AttributeValue>
</Attribute>
</Action>
</Request>
I would like to define an obligation with three obligation expressions corresponding to each of the above resource attributes. How do I do that with ALFA?
First of all, do note your XACML request is actually a XACML 2.0 request whereas ALFA outputs a XACML 3.0 set of policies. So you'll have a version mismatch.
Secondly, in ALFA to build an obligation that would contain your two attributes, you would do the following:
namespace stackoverflow{
attribute subjectId{
category = subjectCat
id = "urn:oasis:names:tc:xacml:1.0:subject:subject-id"
type = string
}
attribute resourceId{
category = resourceCat
id = "urn:oasis:names:tc:xacml:1.0:resource:resource-id"
type = string
}
attribute resourceType{
category = resourceCat
id = "resource:type"
type = string
}
attribute actionId{
category = actionCat
id = "urn:oasis:names:tc:xacml:1.0:action:action-id"
type = string
}
obligation displayAttributes = "obligation.displayAttributes"
policy example{
apply firstApplicable
rule example{
permit
on permit{
obligation displayAttributes{
subjectId = subjectId
resourceId = resourceId
resourceType = resourceType
actionId = actionId
}
}
}
}
}
On a side note, it seems your XACML request has a semantic error. What is the English equivalent? Right now you're asking:
Can user 1111 do the action view on either of status or pressure for
resource with id status:of:nariman?
You would typically want to ask for pressure and then for status independently or as a multiple request.

split multi valued dynamic fields in Solr Data import handler

Is it possible to split multivalued dynamic fields?
Schema:
<dynamicField name="*_s" type="string" indexed="true" stored="true" multiValued="true"/>
DIH-config:
<field column="*_s" splitBy="\|" />
It doesn't seem to work. Any help is appriciated!
UPDATE inspired on the comment
<dataConfig>
<dataSource driver="com.microsoft.sqlserver.jdbc.SQLServerDriver"
url="jdbc:sqlserver://${dataimporter.request.sqlserver};databaseName=${dataimporter.request.sqlcatelog};responseBuffering=adaptive;"
user="${dataimporter.request.sqluser}"
password="${dataimporter.request.sqlpassword}"
readOnly="true" batchSize="500"/>
<script><![CDATA[
function SplitDynamicColumn(row, context) {
var fields = context.getAllEntityFields();
// find dynamic columns with 'splitBy' rule
for (var f = 0; f < fields.size(); f++) {
var field = fields.get(f);
var columnMask = field.get('column');
if (columnMask.contains('*') && field.containsKey('splitBy')) {
var columnNameRegex = columnMask.replace('*', '\\w+');
var columns = row.keySet().toArray();
// find columns that match mask
for (var c = 0; c < columns.length; c++) {
var columnName = columns[c];
if (columnName.matches(columnNameRegex)) {
// split column value
var value = row.get(columnName);
if (value !== null) {
var arr = new java.util.ArrayList();
var sp = value.split(field.get('splitBy'));
for (var i = 0; i < sp.length; i++) {
arr.add(sp[i]);
}
row.put(columnName, arr);
}
}
}
}
}
return row;
}
]]></script>
<document name="pages">
<entity name="pages" transformer="RegexTransformer,script:SplitDynamicColumn" query="EXEC A_STORED_PROCEDURE">
<field column="*_s" splitBy="\|" />
</entity>
</document>
</dataConfig>
splitBy is a flag for the RegexTransformer. Make sure you have the transformers sets on that entity properly.
However, more importantly, I do not believe DIH will support the wildcard the way you define it. DIH does support wildcard mapping by trying to match field name to schema name, but that does not allow you to define any transformations.
You may just not be able to combine those two features. One way to get around it is by writing your own custom transformer that does not require an definition with the attribute to run.

nhibernate query logic tests

I'm trying to get setup to use nhibernate against our oracle database.
One of my goals is to test query logic. I started off using sqlite, but ran into problems with many-to-one relationships no pulling in foreign object. Thinking this was a sqlite problem I set up a new oracle database to test against, but I get the same symptoms.
When I run a query against a populated database, it works fine and returns results which properly lazy load foreign objects as they are referenced in code.
the query logic tests(contained with in a mstest assembly) return nulls instead of foreign object.
The differences between the two querys:
1. The test query creates,saves and flushes the data just before
calling the query.
2. The test configuration includes steps needed to export the mapped schema
into test database, uses a different default schema and connection string.
3. The test query happens in a mstest unit test assembly.
I have confirmed:
1. That running query against real database works even when run from the unit test
assembly.
2. That the test data is being save in the test database schema.
3. That the foreign key reference is created in the test database.
4. That the primary keys are being created in both tables used in query.
I suspect that im missing a step when saving the data to the test database, so I will share that code, I can add the configuration code if requested.
var session = DbSession.Load(ConnModes.UnitTest);
var uil = new List<UserInfo>();
uil.Add(new UserInfo { Id = -1, FullName = "Fred Flintstone", LoginName = "fredflint" });
uil.Add(new UserInfo { Id = -1, FullName = "Barney Ruble", LoginName = "barnrubl" });
uil.Add(new UserInfo { Id = -1, FullName = "Bam Bam", LoginName = "bambam" });
foreach (var f in uil)
{
session.Save(f);
}
var rightNow = DateTime.Now;
var x = new List<FacilityRouteFormula>();
x.Add(new FacilityRouteFormula { Id = -1, TrackingFacilityId = 2, Formula = "a formula1", ComponentGroupName = "Comp 0", UserId = 1, CreationDate = rightNow.AddMinutes(5) });
x.Add(new FacilityRouteFormula { Id = -1, TrackingFacilityId = 2, Formula = "a formula2", ComponentGroupName = "Comp 0", UserId = 1, CreationDate = rightNow.AddMinutes(3) });
x.Add(new FacilityRouteFormula { Id = -1, TrackingFacilityId = 2, Formula = "a formula3", ComponentGroupName = "Comp 0", UserId = 1, CreationDate = rightNow.AddMinutes(4) });
x.Add(new FacilityRouteFormula { Id = -1, TrackingFacilityId = 2, Formula = "a formula4", ComponentGroupName = "Comp 0", UserId = 1, CreationDate = rightNow.AddDays(1) });
x.Add(new FacilityRouteFormula { Id = -1, TrackingFacilityId = 2, Formula = "a formula5", ComponentGroupName = "Comp 0", UserId = 1, CreationDate = rightNow });
foreach (var f in x)
{
session.Save(f);
}
session.Flush();
var uidata2 = (from uid in session.Query<UserInfo>() select uid).ToList();
var data = (from uid in session.Query<FacilityRouteFormula>() select uid).ToList();
var q = (from frf in session.Query<FacilityRouteFormula>()
where frf.ComponentGroupName == "Comp 0" &&
frf.TrackingFacilityId == 2
orderby frf.CreationDate descending
select frf).ToList();
Assert.IsNotNull(q[0].User);
Assert.AreEqual("fredflint", q[0].User.LoginName);
Here is the query against "real" database.
var s = DbSession.Load(ConnModes.Dev );
var q = (from frf in s.Query<FacilityRouteFormula>()
where frf.ComponentGroupName == "Comp 0" &&
frf.TrackingFacilityId == 2
orderby frf.CreationDate descending
select frf).ToList();
mapping files as requested:
FacilityRouteFormula:
<id name="Id" column="N_FACILITY_ROUTE_FORMULA_ID" type="long" unsaved-value="-1">
<generator class="native" >
<param name="sequence">SEQ_FACILITY_ROUTE_FORMULA</param>
</generator>
</id>
<property name="TrackingFacilityId" column="N_TRACKING_FACILITY_ID" type="long" />
<property name ="ComponentGroupName" column="C_COMPONENT_GROUP_NAME" type="string"/>
<property name="CreationDate" column="D_CREATION_DATE" type="DateTime"/>
<property name="UserId" column="N_USER_ID" type="int" not-null="true" />
<property name="Formula" column="C_FORMULA" type="string" not-null="true" />
<many-to-one insert="false" update="false" lazy="false" name="User" fetch="select">
<column name="N_USER_ID" sql-type="NUMBER" not-null="true" />
</many-to-one>
UserInfo:
<id name="Id" column="N_USER_ID" type="int" unsaved-value="-1" >
<generator class="native" >
<param name="sequence">SEQ_USER_ID</param>
</generator>
</id>
<property name="FullName" column="C_USER_FULL_NAME" type="string" not-null="true" />
<property name="LoginName" column="C_LOGIN_NAME" type="string" not-null="true" />
I think you need to clear the cache something like this.
session.Save(f);
session.Flush();
session.Evict(f);