SSAS: Programmatically create attribute relationships - c#

Using AMO I can happily confirm the existance of two dimension attributes. I'd like to create a relationship. The following (result) returns a result code of 0 what ever that means however after processing the cube there is no relation. Suggestions?
// confirm db exists
db = objServer.Databases.FindByName(strCubeDBName);
// find the dimension
string dimName = "Product";
Dimension dim = db.Dimensions.FindByName(dimName);
attrSource = dim.Attributes.FindByName("Spanish Product Subcategory Name");
if (attrSource != null)
Console.WriteLine(attrSource + " - source attribute exists");
else
throw new Exception(attrSource + " - source attribute does not exist");
attrRelated = dim.Attributes.FindByName("French Product Subcategory Name");
if (attrRelated != null)
Console.WriteLine(attrRelated + " - Related attribute exists");
else
throw new Exception(attrRelated + " - Related attribute does not exist");
int result;
result = attrSource.AttributeRelationships.Add(new AttributeRelationship(attrRelated));
Console.WriteLine(result);
dim.Process(ProcessType.ProcessUpdate);

After adding the new attribute relationship, you need to call Update on the dimension. In your code above, just before calling Process, add the following line:
dim.Update(UpdateOptions.ExpandFull | UpdateOptions.AlterDependents)

Related

Empty value in attribute | Plugin CRM C#

I change only 1 field in the interface - "telephone1", and leave the second one unchanged, in the end I want field 3 to contain both 1 changed field and 2 field unchanged, but for some reason it is empty, although it contains values, it also works and vice versa. "InputParametres" as I understand it is a bad idea, but what other options are there?
https://i.imgur.com/7G3rRVK.png
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
try
{
var createReq = new CreateRequest() { Parameters = context.InputParameters };
var res = createReq.Target; // Has type Entity
// Получить целевой объект из входных параметров
Entity entityInput = (Entity)context.InputParameters["Target"];
// entityInput.Attributes["telephone3"] = entityInput. + ";" + entityInput.Attributes["telephone2"];
entityInput.Attributes["telephone3"] = res.GetAttributeValue<string>("telephone1") + ";" + res.GetAttributeValue<string>("telephone2");
// service.Update(entityInput);
}
catch (Exception ex)
{
throw new Exception($"Error in update telephone3 - {ex.Message}");
}
}
else
{
throw new InvalidPluginExecutionException($"Плагин {nameof(Class1)} был зарегистрирован неправильно");
}
Target will have only changed attributes and it’s values. If you need the values from unchanged attributes (fields) you have to use PreImage to consume them.
You can register PreImage in Plug-in registration tool similar to steps, filtering attributes, etc.
Read more

address1_latitude and address1_longitude is not getting from RetrieveMultiple

Hi i have tried to get address1_latitude and address1_longitude from CRM using CRM SDK here is mu code
var querybyattribute11 = new QueryByAttribute("account");
querybyattribute11.ColumnSet = new ColumnSet("name", "address1_city", "statuscode", "address1_postalcode", "address1_latitude", "address1_longitude");
querybyattribute11.Attributes.AddRange("name");
querybyattribute11.Values.AddRange("ASSOCIATED COMBUSTION INC");
EntityCollection entities = service.RetrieveMultiple(querybyattribute11);
foreach (Entity item in entities.Entities)
{
// Console.WriteLine("Name: {0}. Id: {1}", role.Name, role.Id);
list += item.Attributes["name"].ToString() + " " + item.Attributes["address1_longitude"] .ToString() + "\n";
}
But I am not geting it item.Attributes["address1_longitude"]
error message is
'The given key was not present in the dictionary.'
It might be because it's null.
Try either one of these 2 options:
item["address1_longitude"] (shouldn't raise exception, it would return null if blank, otherwise the address longitude)
To check if the column exists:
item.Attributes.ContainsKey("address1_longitude")

'The given key was not present in the dictionary' - but the key exists

I am currently developing a MS Dynamics CRM 2013 - Plugin.
When I try to assign a string-value to a key of a field of an entity it gives me the 'keynotfound'-exception.
This leaves me clueless, because I can verify the key is existing. The key I give is also written correctly, and the data types are compatible, too.
Here's some extra info:
I tried resolving the issue with a server reboot. Nothing.
Remote Debugging is not an option.
I swapped "retrieved.EntityCollection.Entities[i][forField]" with retrieved.EntityCollection.Entities[i]["new_name"] and everything was working fine (kind of pointing out the obvious here, but "new_name" is not the key I try to access).
The execution stops # "if (retrieved.EntityCollection.Entities[i][forField].ToString() != "" && !overwriteExisting)"
Have you got an idea to help me out?
public void GenerateNumberForEntityCollection(string target)
{
try
{
// variables for number generation
bool overwriteExisting = (bool)preImageEntity["new_overwriteexisting"];
int suffixstart = (int)preImageEntity["new_suffixstart"];
string forField= preImageEntity["new_forfield"].ToString();
string prefix = preImageEntity["new_prefix"].ToString();
string postfix = preImageEntity["new_postfix"].ToString();
string separator = preImageEntity["new_separator"].ToString();
// Build query to get all the entries
RetrieveMultipleResponse retrieved;
int PageNumber = 1;
string PagingCookie = string.Empty;
int PageSize = 5000;
string[] Columns = { forField };
QueryExpression query = new QueryExpression()
{
EntityName = target,
ColumnSet = new ColumnSet(Columns),
PageInfo = new PagingInfo()
{
PageNumber = 1,
Count = PageSize
}
};
do
{
if (PageNumber != 1)
{
query.PageInfo.PageNumber = PageNumber;
query.PageInfo.PagingCookie = PagingCookie;
}
RetrieveMultipleRequest retrieve = new RetrieveMultipleRequest();
retrieve.Query = query;
retrieved = (RetrieveMultipleResponse)service.Execute(retrieve);
// Now that all entities are retrieved, iterate through them to gen. the numbers
int i = 0;
foreach (Entity entity in retrieved.EntityCollection.Entities)
{
if (retrieved.EntityCollection.Entities[i][forField].ToString() != "" && !overwriteExisting)
{
//continue;
}
else
{
retrieved.EntityCollection.Entities[i][forField] = prefix + separator + suffixstart.ToString() + separator + postfix;
}
suffixstart++;
service.Update(retrieved.EntityCollection.Entities[i]);
i++;
}
if (retrieved.EntityCollection.MoreRecords)
{
PageNumber++;
PagingCookie = retrieved.EntityCollection.PagingCookie;
}
} while (retrieved.EntityCollection.MoreRecords);
}
catch (Exception e)
{
tracing.Trace("GenerateNumberForEntityCollection: Failed: {0}", e.ToString());
}
}
How did you verify that the key exists?
If the data in a field is null, the Entity instance will not contain that key, even if you specify it in the query's ColumnSet.
This will return you a boolean, indicating if the key exists in the Entity. You can do this control before attempting to read the attribute.
var attributeExists = retrieved.EntityCollection.Entities[i].Contains(forField)
The control below you've done will result in the exception you're getting if the field is null. Just make sure that the attribute exists before.
retrieved.EntityCollection.Entities[i][forField].ToString() != ""
Additionally, you'll get a null reference exception if no records were returned from the query. Make you do a null check on retrieved.EntityCollection.Entities.
When you are querying data in Dynamics CRM it is important to know that record fields having null values in the database are not included in the Attributes collection of the Entity instances being returned.
Getting a value from an Entity's Attribute with this construct:
var value = retrieved.EntityCollection.Entities[i][forField].ToString();
succeeds when attribute forField already has a value in the database, but fails when its current value is null.
Therefore the preferred method to get the attribute values from an entity is GetAttributeValue<T>, like this:
var value = retrieved.EntityCollection.Entities[i].getAttributeValue<string>(forField);
This method returns the value when the attribute exists in the attribute collection, otherwise it returns null.
If any of the fields among
(new_forfield,new_prefix,new_postfix,new_separator) has null value,
that column does not present in the retrieved object and you are trying to get the value of null column preImageEntity["new_forfield"] which will throw keynotfound'-exception ,
so change the code
string forField= preImageEntity["new_forfield"].ToString();
string prefix = preImageEntity["new_prefix"].ToString();
string postfix = preImageEntity["new_postfix"].ToString();
string separator = preImageEntity["new_separator"].ToString();
to
string forField = preImageEntity.Attributes.Contains("new_forfield")? preImageEntity["new_forfield"].ToString():"";
string prefix = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_prefix"].ToString() : "";
string postfix = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_postfix"].ToString() : "";
string separator = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_separator"].ToString() : "";
this will check for field, if it exists than will parse the value to
string else will assign empty string.

Cannot add an entity with a key that is already in use (LINQ)

I get this error Cannot add an entity with a key that is already in use. when I run the code below.
Tables:
What am i missing?
private void CopyAllPageObjects(int fromPageID, int toPageID)
{
CMSDataContext _db = new CMSDataContext();
// Copy page objects
var originalPageObjects = (from x in _db.CMSPageObjects
where x.PageID == fromPageID
select x);
List<CMSPageObject> newPageObjects = new List<CMSPageObject>();
foreach (CMSPageObject po in originalPageObjects)
{
CMSPageObject newPageObject = new CMSPageObject();
newPageObject.PageID = toPageID;
newPageObject.CMSObjectID = po.CMSObjectID;
newPageObject.Name = po.Name;
newPageObject.Sorting = po.Sorting;
newPageObjects.Add(newPageObject);
// Copy page object attribute values
var originalPoavs = (from x in _db.CMSPageObjectAttributeValues
where x.CMSPageObjectID == po.ID
select x);
List<CMSPageObjectAttributeValue> newPoavs = new List<CMSPageObjectAttributeValue>();
foreach (CMSPageObjectAttributeValue poav in originalPoavs)
{
CMSPageObjectAttributeValue newPoav = new CMSPageObjectAttributeValue();
newPoav.CMSAttributeID = poav.CMSAttributeID;
newPoav.CMSPageObjectID = newPageObject.ID;
newPoav.LCID = poav.LCID;
newPoav.Value = poav.Value;
newPoavs.Add(newPoav);
}
_db.CMSPageObjectAttributeValues.InsertAllOnSubmit(newPoavs);
}
_db.CMSPageObjects.InsertAllOnSubmit(newPageObjects);
_db.SubmitChanges();
}
I was getting this error and it was because I had forgotten to set the Primary Key field in the database to "Identity Specification" (auto-increment). But that is just a guess
It looks like you're trying to add an object, while another one with same primary key exists. Are PageID or CMSObjectID primary keys? Or CMSAttributeID?
You might also want to share more data about how your data tables look like.
Update: after you added database struct, I would look closer at this line:
newPoav.CMSPageObjectID = newPageObject.ID;
the newPageObject.ID is probably not known at this time, because you didn't add the object to the DB yet (I suspect ID is identity). I think you could use:
newPoav.CMSPageObject = newPageObject
Seems you are missing primary key or an unique key on CMSPageObject table. Please try to verify the keys in the database. I had same issue since I had missed the PK on the table.
Cheers.
you have to add some code just for testing if the list newPoavs have a key exist already in the database
you can just add this
foreach (CMSPageObjectAttributeValue poav in originalPoavs)
{
CMSPageObjectAttributeValue newPoav = new CMSPageObjectAttributeValue();
newPoav.CMSAttributeID = poav.CMSAttributeID;
newPoav.CMSPageObjectID = newPageObject.ID;
newPoav.LCID = poav.LCID;
newPoav.Value = poav.Value;
newPoavs.Add(newPoav);
if(_db.CMSPageObjectAttributeValues.Any(x=>x.LCID == newPoav.LCID & x.CMSAttributeID == newPoav.CMSAttributeID & x.CMSPageObjectID == newPoav.CMSPageObjectID ))
MessageBox.Show("Already exist");
}
just to test your values

How to get underlying type from typed DataSet

I've been searching a lot but I haven't found anything about this question. I'm making a log of my app and I'm printing types of variables and their values. I want to do the same for every object I receive as parameter, and for every object I return too. So I'm returning a typed dataset (MyDataSet that's defined as MyDataSetType e.g.) but I can't retrieve MyDataSetType name.
I have a method that given a dataset, returns a string with all the content. Something like this:
string GetLogStringFromDataSetParameter(System.Data.DataSet incomingDataSet)
{
StringBuilder strReturn = new StringBuilder();
strReturn.Append("DataSet (type ");
strReturn.Append(GetTypeName(incomingDataSet));
strReturn.Append("). ");
// .. do some validations
strReturn.Append("Contains ");
strReturn.Append(incomingDataSet.Tables.Count);
strReturn.Append(" tables.");
for (int i = 0; i < incomingDataSet.Tables.Count; i++)
{
System.Data.DataTable table = incomingDataSet.Tables[i];
strReturn.Append(" Tabla " + table.TableName + " (" + i + ") ");
strReturn.Append(<Method to list table content>);
}//yes, this could have been a foreach loop...
return FormatStringToLog(strReturn);
} //end
As you can see, I'm using my own method GetTypeName to retrieve de name of my typed dataset. I've made this method after some investigation through this site:
public static string GetTypeName<T>(T parameter)
{
string strReturn = typeof(T).Name;
if (strReturn.IndexOf("Nullable") >= 0)
strReturn = Nullable.GetUnderlyingType(typeof(T)).Name;
else if (strReturn.IndexOf("List") >= 0)
{
strReturn = "List of " + typeof(T).GetGenericArguments()[0].Name;
if (strReturn.IndexOf("Nullable") >= 0)
strReturn = "List of " + Nullable.GetUnderlyingType(typeof(T).GetGenericArguments()[0]).Name;
}
return strReturn;
}
When I'm inside of GetLogStringFromDataSetParameter method, if I try typeof(MyDataSet) it returns correctly MyDataSetType. But when I make the call to GetTypeName it returns DataSet only, the generic type. Why is this? Is there any way to retrieve correctly MyDataSetType without calling directly to typeof()?
I hope I've explained everything clear enough. Thanks in advance.
That is because typeof(T) has nothing to do with the incoming Dataset type.
At compile-time the method is instantiated for the plain Datset type, and T is of type Dataset.
To solve it, simply use parameter.GetType() instead of typeof(T)

Categories