I have a custom entity A, which contains an annotation column (a built in entity that support upload files). I want to be able to read the annotation id for the entity record i get when a plugin is triggered.
The entity has all attributes i am except the annotation in any form, no referenced entity. It is worth to note that annotation entity is listed in the relationship tab but there is no reference to annotation field in the fields view in Dynamics online.
How can i lookup or get the annotation id in the entity A in a custom plugin.
The plugin triggers on the create message from custom entity A, since it has all the columns i want to process in addition the file uploaded in the annotation entity.
I looked at the sample sdk sample, but it is not useful since i want to get the annotation id first before retrieving it.
https://learn.microsoft.com/en-us/previous-versions/dynamicscrm-2016/developers-guide/gg328429(v=crm.8)
Any pointers or sample are appreciated it.
There is a one-to-many relationship from your custom entity to the annotation entity, because there can be many notes (and attachments) for each custom entity record.
Your plugin should create a new annotation record and set the objectid and objecttypecode fields on that annotation record to the current custom record that was just created.
Here's an example that uploads a simple text file and relates it to a custom entity record that was just created:
var newId = <new just-created custom entity record id goes here>;
var sampleFileText = "Hello World";
var sampleFileBytes = Encoding.ASCII.GetBytes(sampleText);
var sampleFileBase64 = System.Convert.ToBase64String(fileBytes);
var annotation = new Entity("annotation");
annotation.Attributes["objectid"] = new EntityReference("new_entity", newId); // <- Your custom entity name and new id here
annotation.Attributes["objecttypecode"] = "new_entity"; // <- Your custom entity name here
annotation.Attributes["subject"] = "Uploaded File";
annotation.Attributes["documentbody"] = sampleFileBase64 ;
annotation.Attributes["mimetype"] = #"text/plain";
annotation.Attributes["notetext"] = "Uploaded File";
annotation.Attributes["filename"] = "UploadedFile.txt";
Service.Create(annotation);
Related
I want to create a one method using which i can Add/Update entity using Entity Framework 2.0-Preview.
I am using Insert Update Pattern.
For more Ref: https://msdn.microsoft.com/en-us/data/jj592676.aspx (Last example)
Below is a method code:
public string AttachEntity(Book book)
{
_context.Entry(book).State = (book.Id == 0)
? Microsoft.EntityFrameworkCore.EntityState.Added
: Microsoft.EntityFrameworkCore.EntityState.Modified;
string msg = $"Book details {_context.Entry(book).State} Successfully";
_context.Book.Attach(book);
_context.SaveChanges();
return msg;
}
and got below error:
InvalidOperationException: The property 'Id' on entity type 'Book' has
a temporary value while attempting to change the entity's state to
'Unchanged'. Either set a permanent value explicitly or ensure that
the database is configured to generate values for this property.
However Id is auto generated for book table.
and below urls for that action:
[For add] Home/AttachEntity?Id=1&Title=4th book&Description=New book added by attach method&Price=120&AuthorId=2
[For update] Home/AttachEntity?Title=4th book&Description=New book added by attach method&Price=120&AuthorId=2
To preface this question: my problem is not because I'm directly setting a key property in my model entity object (which is the cause of the issue in other search results for the same exception message).
I'm making heavy use of composite keys in my application, here's a simplified version of my current DB schema (key fields in *asterisks*):
Tenants( *TenantId*, ... )
Categories( *TenantId*, *CategoryId*, ... )
Documents( *TenantId*, *DocumentId*, CategoryId, ... )
The Documents table has FK relationships with both Tenants and Categories, both using the same Documents.TenantId column. The Documents.CategoryId column is NULLable.
When I do something like this, I get the exception:
Tenant tenant = GetTenant( 123 );
Document doc = tenant.Documents.First();
Category newCategory = new Category();
newCategory.TenantId = 123;
dbContext.Categories.Add( newCategory );
doc.Category = newCategory; <-- exception is thrown on this line, without calling dbContext.SaveChanges() at all.
I believe the exception is because setting Category on the Document instance causes the TenantId property to be set indirectly by EF (because it's part of the Documents -> Categories FK association.
What is the solution?
Workaround Update
I'm able to hack it by creating the new Category entities then saving them, to get the IDENTITY values back, then setting the Document properties directly:
Tenant tenant = GetTenant( 123 );
Document doc = tenant.Documents.First();
Category newCategory = new Category();
newCategory.TenantId = 123;
dbContext.Categories.Add( newCategory );
dbContext.SaveChanges();
doc.CategoryId = newCategory.CategoryId
dbContext.SaveChanges();
But ideally I'd like this to work in a single call to SaveChanges() and using the Entity Model Navigation Properties instead of scalar attribute properties.
For this initial problem, I worked-around it using the "Workaround Update" I posted to my original posting.
However this problem happened again for a different entity type (again, with a composite key involved in a foreign-key) and I noticed that EF throws the exception even if you call dbContext.Entry() on any entity in the graph while the new entity is in the Added state - but it does not throw the exception again if you re-call Entry() or even SaveChanges(), and in fact it saves the new entities correctly in spite of the initial exception - so I'm thinking this might just be a bug in EF.
Here's essentially what I have now:
Tenant tenant = GetTenant( 123 );
Document doc = tenant.Documents.First();
Category newCategory = new Category();
newCategory.TenantId = 123;
dbContext.Categories.Add( newCategory );
doc.CategoryId = newCategory.CategoryId
try {
dbContext.Entry( doc );
}
catch(InvalidOperationException) {
}
dbContext.SaveChanges();
It's ugly, but works - and avoids having to call SaveChanges twice.
I have a customer which I want to update in the repository.
var customer = new Customer{ Name = "Test" }
The customer has still more properties which are null, because I have not loaded them before to the client. Thus these properties have all their default values like null or 0.
What do I have to do with latest EF 6, that only the property Name is updated and the other properties from the customer are not overwritten?
1.) How would I have to query/update the customer?
2.) What would happen if the customer has a collection of and he has changed some properties of some meetings - but not all properties - how would then be the override behavior?
UPDATE pseudo code
Open context
Get customer
Close context
Open context
Update customer.name
SAveChanges
Close context
The custom.name is not saved, why?
You can't do it natively without getting the whole entiy first, which is obviously 2 db hits.
There is however an extension you can use that does what you want:
https://github.com/loresoft/EntityFramework.Extended/wiki/Batch-Update-and-Delete
Assuming you already have your model generated and it has a name of "MyEntities" and you should have a customer ID if you are updating an existing. Here is a solution using c#.
using(MyEntities db = new MyEntities()) {
//this will retreieve the customer based on ID
Customer cust = db.Customers.FirstOrDefault(c => c.CustomerID == custID);
//you can update each column
cust.Name = "Test";
//save the changes to the entity
db.SaveChanges();
}
Below is my schema generation code, Two variables (storeIdForSurvey & questionIdForAnswer) are not being auto generated in the model class( Survey & Question), though they are present the in auto generated dao classes (SurveyDao & QuestionDao).
Object Oriented description of the domain is as : User has Store, Store has Survey,Survey has FollowupItems, Survey has Category, Category has Question, Question has History, Question has Answer.
private static void addUser(Schema schema) {
//User
Entity user = schema.addEntity("User");
user.addIdProperty();
user.addStringProperty("districtId");
user.addStringProperty("employeeId");
user.addStringProperty("name");
user.addStringProperty("sessionToken");
user.addStringProperty("userId");
//Store
Entity store = schema.addEntity("Store");
// foreign key
Property userIdForStore = store.addLongProperty("userIdForStore").getProperty();
store.addToOne(user, userIdForStore);
user.addToMany(store, userIdForStore);
store.addIdProperty();
store.addStringProperty("storeId");
store.addStringProperty("address");
store.addStringProperty("city");
store.addStringProperty("storeName");
store.addStringProperty("state");
store.addStringProperty("zip");
store.addStringProperty("storeManagerName");
store.addBooleanProperty("isSurveyHistoryAvailable");
//Survey
Entity survey = schema.addEntity("Survey");
//foreign key
Property storeIdForSurvey = survey.addLongProperty("storeIdForSurvey").getProperty();
survey.addToOne(store, storeIdForSurvey); // one store can have one survey at a time
store.addToOne(survey, storeIdForSurvey);
survey.addIdProperty();
survey.addStringProperty("surveyId");
survey.addStringProperty("dmSignImagePath");
survey.addStringProperty("dmSignImageName");
survey.addStringProperty("smSignImagePath");
survey.addStringProperty("smSignImageName");
survey.addStringProperty("startlatitude");
survey.addStringProperty("startlongitude");
survey.addStringProperty("submitLatitude");
survey.addStringProperty("submitLongitude");
survey.addStringProperty("acknowledgedBy");
survey.addStringProperty("deliveredBy");
survey.addStringProperty("name");
survey.addStringProperty("createdBy");
survey.addStringProperty("description");
survey.addStringProperty("storeId");
survey.addStringProperty("districtManager");
survey.addDateProperty("startDate");
survey.addDateProperty("submitDate");
survey.addDateProperty("syncDate");
survey.addDateProperty("createdDate");
survey.addDateProperty("actionItemAssignDate");
survey.addDateProperty("actionItemDueDate");
survey.addDoubleProperty("score");
//FolloupItems
Entity followupItem = schema.addEntity("FollowupItem");
//foreign key
Property surveyIdForFollowupItem = followupItem.addLongProperty("surveyIdForFollowupItem").getProperty();
followupItem.addToOne(survey, surveyIdForFollowupItem);
survey.addToMany(followupItem, surveyIdForFollowupItem);
followupItem.addIdProperty();
followupItem.addStringProperty("assignedTo");
followupItem.addStringProperty("comment");
followupItem.addStringProperty("photoName");
followupItem.addStringProperty("photoURL");
followupItem.addDateProperty("assignedDate");
followupItem.addDateProperty("dueDate");
followupItem.addDateProperty("expeireDate");
//Category
Entity category = schema.addEntity("Category");
//foreign key
Property surveyIdForCategory = category.addLongProperty("surveyIdForCategory").getProperty();
category.addToOne(survey, surveyIdForCategory);
survey.addToMany(category, surveyIdForCategory);
category.addIdProperty();
category.addStringProperty("categoryId");
category.addStringProperty("name");
category.addStringProperty("weight");
category.addStringProperty("surveyId");
category.addDoubleProperty("totalScore");
category.addIntProperty("sortOrder");
category.addBooleanProperty("completionStatus");
category.addBooleanProperty("hasActionItem");
//Question
Entity question = schema.addEntity("Question");
//foreign key
Property categoryIdForQuestion = question.addLongProperty("categoryIdForQuestion").getProperty();
question.addToOne(category, categoryIdForQuestion);
category.addToMany(question, categoryIdForQuestion);
question.addIdProperty();
question.addStringProperty("questionId");
question.addDateProperty("startDate");
question.addDateProperty("endDate");
question.addStringProperty("statement");
question.addStringProperty("type");
question.addStringProperty("weight");
question.addStringProperty("surveyCategoryName");
question.addIntProperty("displayOrder");
question.addBooleanProperty("naFlag");
question.addBooleanProperty("isRequired");
//Question History
Entity questionHistory = schema.addEntity("questionHistory");
//foreign key
Property questionIdForQuestionHistory = questionHistory.addLongProperty("questionIdForQuestionHistory").getProperty();
questionHistory.addToOne(store, questionIdForQuestionHistory);
question.addToMany(questionHistory, questionIdForQuestionHistory);
questionHistory.addIdProperty();
questionHistory.addStringProperty("questionId");
questionHistory.addStringProperty("secondLastHistory");
questionHistory.addStringProperty("lastHistory");
//Answer
Entity answer = schema.addEntity("Answer");
//foreign key
Property questionIdForAnswer = answer.addLongProperty("questionIdForAnswer").getProperty();
question.addToOne(answer, questionIdForAnswer);
answer.addToOne(question, questionIdForAnswer);
answer.addIdProperty();
answer.addStringProperty("projectType");
answer.addStringProperty("assignedTo");
answer.addStringProperty("comment");
answer.addStringProperty("photoUrl");
answer.addStringProperty("photoNmae");
answer.addStringProperty("selectedOption");
answer.addDateProperty("assignedDate");
answer.addDateProperty("dueDate");
answer.addDateProperty("expireDate");
answer.addDoubleProperty("score");
}
please read the documentation carefully:
public ToOne addToOne(Entity target, Property fkProperty)
Adds a to-one relationship to the given target entity using the given given
foreign key property (which belongs to this entity).
This means the following statement is correct:
Property storeIdForSurvey = survey.addLongProperty("storeIdForSurvey").getProperty();
survey.addToOne(store, storeIdForSurvey);
but the next statement is incorrect since the Property storeIdForSurvey is not member of the Entity store:
store.addToOne(survey, storeIdForSurvey);
Try to use this statement instead:
store.addToOneWithoutProperty("Survey", survey, "storeIdForSurvey");
When I have an entity that holds a reference to a singular entity I can create an EntityKey and assign that value to the EntityNameReference.Value property. It works perfectly and like a charm.
If I have an entity that holds a reference to multiple entities I cannot succeed in doing the same thing. Suppose an entity called Application that has a property that contains references to Modules (so Application has a List property called Modules).
How can I programmatically attach entity keys to that kind of property?
I tried something like this, without any success:
foreach(int idModule in selectedModules)
{
Module m = new Module();
m.EntityKey = new EntityKey("myModel.ModuleSet", "idModule", idModule);
ctx.Attach(m); //Here I have an exception
app.Modules.Add(m);
Thanks a lot for your help.
Marco
Does Module have Application navigation property? It should.
I would write something like:
foreach(int idModule in selectedModules)
{
Module m = new Module();
m.EntityKey = new EntityKey("myModel.ModuleSet", "idModule", idModule);
m.Application = app;
app.Modules.Add(m);
}
ctx.SaveChanges();