CRM Dynamics Upsert - Insert OptionSet - dynamics-crm

I am trying to update/Insert Contact Entity. While simple text fields are saving, having difficulties updating OptionSet. For ex. new_gender field is an option set (Male/Female).
contact["new_gender"] = new OptionSetValue(1); //Does not work
contact["new_gender"] = 1; //Does not work
Error says:
"new_gender should have the Integer value of Enum. Please supply it in the format - <entitysetname>(<attributename>=100000000)"
Any help is appreciated!!

Custom OptionSets have a prefix named Option Value Prefix. I guess in you case it's "10000".
Try it this way:
contact["new_gender"] = new OptionSetValue(100000001);

You can define an Enum something like
public enum Gender
{
Male = 10000001,
Female = 10000002
}
and set the attribute of gender
contact["new_gender"] = new OptionSetValue((int)Gender.Male);
also, you can get the gender value like this;
int value = ((OptionSetValue)contact[new_gender]).Value;

Related

Getting a column by string name

I'm trying to update a record given the customer Id, the row Id, and a dynamic column name.
Thus far I have the following, with the trouble spot marked by ***:
public void UpdateRecord(int Id, string rval, string column, string value)
{
var rId = GetRvalId(rval);
var entry = _context.Customers
.Where(x => x.Id == Id && x.RVals.Id == rId && x.***column?*** == column).First();
entry = value;
}
I haven't been able to find a good example of how to do this.
Addition after comments at the end
The reason you couldn't find examples is because it is not a good design.
Your method is very error prone, difficult to test and horrible to maintain. What if someone types the incorrect column name? What if you try to assign a string to the customer's birthday? And even if you would implement some string checking for column names and proposed values, then your program wouldn't work anymore after someone changes the names or the types of the columns.
So let's redesign!
Apparently you have a Customer with an Id and a property Rvals. This property Rvals also has a property Id.
You also have a function GetRValId that can convert a string rval to an int rvalId.
What you want, is given an Id and a string rval, you want to update one of the columns of the first Customer with this Idand rValId.
Side questions: Can there be more than one Customer with Id? In that case: are you sure Id is an ID? What do you want if there are more matching Customers? Update all customers or update only the first one? Which customer do you define as the first customer?
Leaving the side questions aside. We want a function signature that reports errors at compile time if you use non-existing customer properties, or if you try to assign a string to a Birthday. Something like this perhaps?
Update the name of the customer:
int customerId = ...
string rval = ...
string proposedName = "John Doe";
UpdateCustomerRecord(id, rval, customer => customer.Name = proposedName);
Update the Birthday of the customer:
DateTime proposedBirthday = ...
UpdateCustomerRecord(id, rval, customer => customer.Birthday = proposedBirthday)
This way you can't use any column that does not exist, and you can't assign a string to a DateTime.
You want to change two values in one call? Go ahead:
UpdateCustomerRecord(id, rval, customer =>
{
customer.Name = ...;
customer.Birthday = ...;
});
Convinced? Let's write the function:
public void UpdateCustomerRecord(int customerId, string rval, Action<Customer> action)
{
// the beginning is as in your function:
var rId = GetRvalId(rval);
// get the customer that you want to update:
using (var _Context = ...)
{
// get the customer you want to update:
var customerToUpdate = _Context.Customers
.Where(customer => customer.Id == Id
&& customer.RVals.Id == rId)
.FirstOrDefault();
// TODO: exception if there is no customerToUpdate
// perform the action and save the changes
action(customerToUpdate);
_context.SaveChanges();
}
Simple comme bonjour!
Addition after comments
So what does this function do? As long as you don't call it, it does nothing. But when you call it, it fetches a customer, performs the Action on the Customer you provided in the call, and finally calls SaveChanges.
It doesn't do this with every Customer, no it does this only with the Customer with Id equal to the provided Id and customer.RVals.Id == ... (are you still certain there is more than one customer with this Id? If there is only one, why check for RVals.Id?)
So the caller not only has to provide the Id, and the RVal, which define the Customer to update, but he also has to define what must be done with this customer.
This definition takes the form of:
customer =>
{
customer.Name = X;
customer.BirthDay = Y;
}
Well if you want, you can use other identifiers than customer, but it means the same:
x => {x.Name = X; x.BirthDay = Y;}
Because you put it on the place of the Action parameter in the call to UpdateCustomerRecord, I know that x is of type Customer.
The Acton statement means: given a customer that must be updated, what must we do with the customer? You can read it as if it was a Function:
void Action(Customer customer)
{
customer.Name = ...
customer.BirthDay = ...
}
In the end it will do something like:
Customer customerToUpdate = ...
customerToUpdate.Name = X;
customerToUpdate.BirthDay = Y;
SaveChanges();
So in the third parameter, called Action you can type anything you want, even call functions that have nothing to do with Customers (probably not wise). You have an input parameter of which you are certain that it is a Customer.
See my earlier examples of calling UpdateCustomerRecord, one final example:
UpdateCustomerRecord( GetCustomerId(), GetCustomerRVal,
// 3rd parameter: the actions to perform once we got the customerToUpdate:
customer =>
{
DateTime minDate = GetEarliestBirthDay();
if (customer.BirthDay < minDate)
{ // this Customer is old
customer.DoThingsThatOldPeopleDo();
}
else
{ // this Customer is young
customer.DoThingsThatYoungPeopleDo();
}
}
}
So the Action parameter is just a simpler way to say: "once you've got the Customer that must be updated, please perform this function with the Customer
So if you only want to update a given property of the customer write something like:
UpdateCustomerRecord(... , customer =>
{
Customer.PropertyThatMustBeUpdated = NewValueOfProperty;
}
Of course this only works if you know which property must be updated. But since you wrote "I am trying to update a specific cell." I assume you know which property the cells in this column represent.
It is not possible to pass the column name as the string value in LINQ. Alternate way to do it, if you have the limited number of the column name which can be passed then it can be achieved as below:
public void UpdateRecord(int Id, string rval, string column, string value)
{
var rId = GetRvalId(rval);
var entry = _context.Customers
.Where(x => x.Id == Id &&
x.RVals.Id == rId &&
(x.column1 == value || column == column1) &&
(x.column2 == value || column == column2) &&
(x.column3 == value || column == column3) &&
(x.column4 == value || column == column4) &&
(x.column5 == value || column == column5) &&
)).First();
entry = value;
}
UpdateRecord(5, "rval", "column1", "value");
UpdateRecord(5, "rval", "column2", "value");
UpdateRecord(5, "rval", "column3", "value");
Here, suppose you have the 5 columns that can be passed while calling the funcion UpdateRecord then you can add the 5 clauses in the WHERE as above.
Other way to do it dynamic LINQ
var entry = db.Customers.Where(column + " = " + value).Select(...);

CRM 2016 + Currency is required if a value exists

I have javascript on my form wherein onchange of a field, currency is set.
For eg i have a field named 'Field1', on change of a value in 'Field1', currency is set and an another money field (say price) is set based on the currency selected.
So the scenario is, when the value from Field1 is removed, currency and price both are set to blank,after then if a value is selected in Field1, eventhough the currency is set it throws an error "Currency is required if a value exists". My Assumption is it throws the error because i am trying to set the price field also after setting the currency.
Below is the code used to set currency.
var arrLookupData = new Array();
var objLookupItem = new Object();
objLookupItem.typename = "transactioncurrency";
objLookupItem.id = varray.id;
objLookupItem.name = varray.name;
arrLookupData[0] = objLookupItem;
Xrm.Page.getAttribute("transactioncurrencyid").setValue(arrLookupData);
Xrm.Page.getAttribute("transactioncurrencyid").fireOnChange();
//Some code
Xrm.Page.getAttribute("core_price").setValue(value);
Kindly suggest.
Make sure you invoke fireOnChange after you set values in fields from Javascript, otherwise the form won't "see" the new data.
Your code would become:
var arrLookupData = new Array();
//
// omitted
//
Xrm.Page.getAttribute("transactioncurrencyid").setValue(arrLookupData);
Xrm.Page.getAttribute("transactioncurrencyid").fireOnChange();

Dynamic Linq on DataTable error: no Field or Property in DataRow, c#

I have some errors using Linq on DataTable and I couldn't figure it out how to solve it. I have to admit that i am pretty new to Linq and I searched the forum and Internet and couldn't figure it out. hope you can help.
I have a DataTable called campaign with three columns: ID (int), Product (string), Channel (string). The DataTable is already filled with data. I am trying to select a subset of the campaign records which satisfied the conditions selected by the end user. For example, the user want to list only if the Product is either 'EWH' or 'HEC'. The selection criteria is dynaically determined by the end user.
I have the following C# code:
private void btnClick()
{
IEnumerable<DataRow> query =
from zz in campaign.AsEnumerable()
orderby zz.Field<string>("ID")
select zz;
string whereClause = "zz.Field<string>(\"Product\") in ('EWH','HEC')";
query = query.Where(whereClause);
DataTable sublist = query.CopyToDataTable<DataRow>();
}
But it gives me an error on line: query = query.Where(whereClause), saying
No property or field 'zz' exists in type 'DataRow'".
If I changed to:
string whereClause = "Product in ('EWH','HEC')"; it will say:
No property or field 'Product' exists in type 'DataRow'
Can anyone help me on how to solve this problem? I feel it could be a pretty simple syntax change, but I just don't know at this time.
First, this line has an error
orderby zz.Field<string>("ID")
because as you said, your ID column is of type int.
Second, you need to learn LINQ query syntax. Forget about strings, the same way you used from, orderby, select in the query, you can also use where and many other operators. Also you'll need to learn the equivalent LINQ constructs for SQL-ish things, like for instance IN (...) is mapped to Enumerable.Contains etc.
With all that being said, here is your query
var productFilter = new[] { "EWH", "HEC" };
var query =
from zz in campaign.AsEnumerable()
where productFilter.Contains(zz.Field<string>("Product"))
orderby zz.Field<int>("ID")
select zz;
Update As per your comment, if you want to make this dynamic, then you need to switch to lambda syntax. Multiple and criteria can be composed by chaining multiple Where clauses like this
List<string> productFilter = ...; // coming from outside
List<string> channelFilter = ...; // coming from outside
var query = campaign.AsEnumerable();
// Apply filters if needed
if (productFilter != null && productFilter.Count > 0)
query = query.Where(zz => productFilter.Contains(zz.Field<string>("Product")));
if (channelFilter != null && channelFilter.Count > 0)
query = query.Where(zz => channelFilter.Contains(zz.Field<string>("Channel")));
// Once finished with filtering, do the ordering
query = query.OrderBy(zz => zz.Field<int>("ID"));

Use enum in LinQ

need help
I have this enum which sets the PayClassNo to Direct and Indirect. I want to use this enum in my LinQ query.
Here's my scratch LinQ query:
var jDef = from jd in context.GetTable<RJVDefinition>()
select new PayrollJVDefinition
{
JVdefNo = jd.JVDefNo,
AccntCode = jd.AccntCode,
AccntDesc = jd.AccntDesc,
PayClass = enum.GetValue(jd.PayClassNo),
IsFixed = jd.IsFixed,
IsEmployee = jd.IsFixed,
IsAR = jd.IsAR,
CreatedByNo = jd.CreatedByNo,
CreatedDate = jd.CreatedDate,
ModifiedByNo = jd.ModifiedByNo,
ModifiedDate = jd.ModifiedDate
};
Need help because I'm not sure if this will work.
You could certainly do the translation in code, similar to your example (using Enum.Parse), but you don't need to. You can use the designer to set the object property type to an enumerated value. See this article for details.
You just need to parse the Enum just use something like
Enum.Parse(jb.PayClassNo, YourEnumType)

Null value cannot be assigned - LINQ query question

I have the following LINQ query:
DataClassesDataContext dc = new DataClassesDataContext();
var query = from contact in dc.Contacts
select new
{
ContactId = contact.ContactId,
LastName = contact.LastName,
FirstName = contact.FirstName,
Addresses = contact.Addresses,
Phones = contact.Phones,
DOB = contact.BirthDate,
LastNote = contact.Notes.Max(n => n.Created), //this line causes the error
Status = contact.ContactStatus.ContactStatusName,
EmailAddress = contact.Emails
};
The line where I get the maximum created date for the notes collection causes the following exception to be thrown:
Exception: The null value cannot be assigned to a
member with type System.DateTime which
is a non-nullable value type.
How do I write the query to allow null values into the LastNote field? The DOB field is defined as DateTime? and has not problem handling nulls.
Think I figured it out.
If I cast the maximum note value to a nullable DateTime it seems to eliminate the exception. The following change worked for me:
LastNote = (Nullable<DateTime>)contact.Notes.Max(n => n.Created)
As others have pointed out, it can also be written using the shorthand notation for a nullable DateTime as follows:
LastNote = (DateTime?) contact.Notes.Max(n => n.Created)
Rewrite that line as:
LastNote = (DateTime?) contact.Notes.Max(n => n.Created),
LastNote = contact.Notes.Max(n => (DateTime?)n.Created)
Couldn't find this on the net so i hope this helps others.
In VB is something like:
LastNote = CType(contact.Notes.Max(n => n.Created), Global.System.Nullable(Of Date))
I think...
You could do that, or you could alter your database schema so that the column 'Created' does not allow nulls.
The scenario is arising because one of the rows comes back with a null value for Created.
If the db didn't allow nulls, the scenario would never occur.

Resources