Dynamics CRM Merge Two Contacts with C# code, modified example from SDK - sdk

I've been trying to get the Merge example in Dynamics CRM 2011 SDK to work.
http://msdn.microsoft.com/en-us/library/hh547408.aspx
I've modified it a bit. I've created two Contacts instead of Accounts (although some variable names in the code might suggest otherwise. For example _account1Id is in fact a GUID for contact1.)
The first Contact record has name, surname and telephone fields filled.
The second Contact record has name, surname and email fields filled.
The part where merge occurs is below. The original code can bee seen from the link at the top.
When I run the example with following modifications, the e-mail address doesn't get merged into the new contact record. What I get is one merged Contact with the values from one of the records, with address data added, but no e-mail. I thought this was supposed to fill empty fields of the primary record with the non-empty fields from the second record.
Being very new to Ms Dynamics CRM, I couldn't understand the reason after much googling and debugging. I'll be glad if someone can give me some feedback about what the problem might be.
Thanks in advance.
_serviceProxy.EnableProxyTypes();
CreateRequiredRecords(); // created two contacts with same name, surname. first record has telephone1 filled, second record has emailaddress filled.
EntityReference target = new EntityReference();
target.Id = _account1Id;
target.LogicalName = Contact.EntityLogicalName;
MergeRequest merge = new MergeRequest();
merge.SubordinateId = _account2Id;
merge.Target = target;
merge.PerformParentingChecks = false;
Contact updateContent = new Contact();
updateContent.Address1_Line1 = "test";
merge.UpdateContent = updateContent;
MergeResponse merged = (MergeResponse)_serviceProxy.Execute(merge);
Contact mergeeAccount =
(Contact)_serviceProxy.Retrieve(Contact.EntityLogicalName,
_account2Id, new ColumnSet(allColumns: true));
if (mergeeAccount.Merged == true)
{
Contact mergedAccount =
(Contact)_serviceProxy.Retrieve(Contact.EntityLogicalName,
_account1Id, new ColumnSet(allColumns: true));
}

That behaviour would be as expected - the Merge will move over child records for you from the subordinate to the master (so potentially opportunities, addresses etc.) but not try to workout which fields you want copied over. The reasoning (I would guess) is the potential business logic implications are endless - do you want to copy over emails? what if all email fields are filled? what about custom fields? And lots of other cases I'm sure everyone can think of.
Edited:
To workaround this, there is a property on the MergeRequest class called UpdateContent. If you update fields on this property, the values will be merged into the parent record.
You can actually see this in the link you has posted:
// Create another account to hold new data to merge into the entity.
// If you use the subordinate account object, its data will be merged.
Account updateContent = new Account();
updateContent.Address1_Line1 = "test";

Related

Looping through list of objects created by createEntry() and editing their properties before doing submitChange()

Good afternoon fellow developers,
I have come across a scenario where I found myself needing to retrieve the list of pending changes from my model and editing a specific property of those entries before sending them to my back-end.
These are new entities I created using the createEntry() method of the OData model v2. But, at the time of creation of said entities, I do not possess the value I need to add to them yet. This is the list of entities I retrieve by using the getPendingChanges() method on my model:
What I need to do is to loop through each of these newly created entities and set a specific property into them before actually sending them to my back-end with the submitChanges() method. Bare in mind that these are entry objects created by the createEntry() method and exist only in my front-end until I am able to submit them with success.
Any ideas that might point me in the right direction? I look forward to reading from you!
I was able to solve this issue in the following way:
var oPendingChanges = this.model.getPendingChanges();
var aPathsPendingChanges = $.map(oPendingChanges, function(value, index) { return [index];});
aPathsPendingChanges.forEach(sPath => oModel.setProperty("/" + sPath + "/PropertyX","valueFGO"));
The first two instructions retrieve the entire list of pendingChanges objects and then builds an array of paths to each individual entry. I then use that array of paths to loop through my list of pending changes and edit into the property I want in each iteration of the loop. Special thanks to the folks at answers.sap for the guidance!

Can't insert same Entity (with different related properties-entity) to another Entity

I have an Entity Product who has a collection of Suppliers (which is also an Entity) and i have a Contract Entity who has a collection of Products. A contract can have multiple products, even 2 same products but with a different Supplier.
When i try to add this second product to my contract (same product but different Supplier this time) EF seems to ignore it and doesn't add it to the Contract.Products collection. No errors but it doens't add it. How can i bypass this behavior or setup my model/logic in a way that i can perform this action?
Code:
// THIS CONTEXT RESIDES IN A USING BLOCK
// THE updateContracts.Products ARE COMING FROM ANOTHER CONTEXT and we are receiving this entity as a parameter
// fetching the contract we are updating from database
Contract contractFromDB = ctx.Contracts.Include(s)(...)Where(p => p.ID == updateContract.ID).FirstOrDefault();
// list to populate the products we have added
List<Product> productsToAddToDBContract = new List<Product>();
foreach (Entity.Product product in updateContract.Products)
{
if (!contractFromDB.Products.Any(prod => prod.ProductName == product.ProductName))
{
// tried detaching it but didn't work
//ctx.Entry(product).State = EntityState.Detached;
productsToAddToDBContract.Add(product);
}
}
foreach (Product product in productsToAddToDBContract)
{
// get these from DB and add those to DB contract products
Product productToAdd = ctx.Products.Include(p=> p.Suppliers).Where(prod=> prod.ProductName == product.ProductName).FirstOrDefault();
if (productToAdd != null)
{
// HERE IS WHERE EF DOESN'T ADD THE SECOND PRODUCT (WHICH IS THE SAME BUT FROM ANOTHER SUPPLIER)
contractFromDB.Products.Add(productToAdd);
}
}
Thank you very much.
EDIT:
I tried to remove the line where i fetched my product from Database
Product productToAdd = ctx.Products.Include(...).Where(...).FirstOrDefault();
and just use the product i already fetched before and passing with the updateContract.Products, i got "The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects."
so i went and attach the product from this iteration:
foreach (Product product in productsToAddToDBContract)
{
// removed this line:
// Entity.Product productToAdd = ctx.Products.Include(p=> p.Suppliers).Where(prod=> prod.ProductName == product.ProductName).FirstOrDefault();
// and added this one
ctx.Products.Attach(product);
contractFromDB.Products.Add(product);
}
then i received '"Attaching an entity of type 'Supplier' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate." Note that the product already has a supplier attached/included to it but from another context (same as the product's context).
This has to regarding the relation of Product and Supplier i think, or maybe because i am using different contexts, i don't know but i will investigate further and post back.
Feel free to contribute in any way of course :)
The issue was my model structure, i can't elaborate on how it was but the related entities relation was not setup correctly, i have created a new entity that holds a ProductId-SupplierId and others, tweaking it till i got what i wanted. The reason why i got these errors (stated above) was because i didn't attach all the related entities when performing actions, when i refered the proper related entities to my product, the errors went away... :)
Hope this helps someone and forgive me for the somewhat unclear solution, i am in the middle of this project and time is an issue, for know the company wants a working solution not a clean one so i didn't not everything down ...
Kind regards!

Vinelab/NeoEloquent - Realtionship to a exisiting node

I am using Vinelab\NeoEloquent for a new project for Neo4j. I have a registration where people can supply interests (as nodes). When registering, first the user is created, then the interests are created (if they don't exist), an given a relationship of "Interested_In" from the person to the interest nodes.
Problem I am having is when the interest already exists (unique by name property) and I just want to create a relationship from the person created and the Interest node.
In my People Model I have (Since 1 person can have many interests):
public function interest(){
return $this->hasMany('App\Models\Interest','Interested_In');
}
In my create user function in my repository I have a section where it searches the Interests and returns one if one exists. Problem is I don't know how to then create the realtionship from People to Interest. I try to save it as
$interests = explode(',',$input['tags']);
$int = new NeoInterestRepository();
foreach($interests as $interest){
$existing = $int->find($interest);
if(count($existing)){
$person->interest()->save($existing);
}else{
$my_interest = $int->create($interest);
$person->interest()->save($my_interest);
}
}
But I get 'Argument 1 passed to Vinelab\NeoEloquent\Eloquent\Relations\HasOneOrMany::save() must be an instance of Illuminate\Database\Eloquent\Model, instance of Illuminate\Database\Eloquent\Collection given'
I see the associate() function but its only for BelongsTo which doesn't seem to apply.
Any ideas?

inserting data in many to many relationship in entity framework

I have two tables (users , messages) which there is many to many relationship for them.
i want to add new messages in message table and allocate massages to current users.
Also i insert data like below:
Message newMessage = Message.CreateMessage("MessageText", "DateTime");
newMessage.Users.Add(new User{..... });
context.SaveChange();
this code will execute a query which add a new user in users table while the users table has some specified users and i don't want to add new user but as i mentioned i want to add new messages in message table and allocate massages to current users.
how should i do that?
The problem is you are creating a new User object with an existing primary key. When SaveChanges() is called EF detects the changes of the entities its already tracking and new entities added. Since your new User object was not tracked by EF, it tries to insert it.
You need to explicitly tell EF that the created user is an existing one. To do that you need to attach it.
Message newMessage = Message.CreateMessage("MessageText", "DateTime");
var user = new User{ Id = "foo" };
context.Users.Attach(user);
newMessage.Users.Add(user);
context.SaveChange();

Cannot insert new Employee entity using InsertOnSubmit()

I'm facing this exception An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported. when I try to insert a new entity into my Employees table (the master one).
There is a relationship between the master Employees table and the details Orders table, and I'm sure that the relationship between these two tables (and specifically Employee.Orders EntitySet) is the cause of the problem since when I removed the relationship, it returns back to insert into Employees table with no problems.
When I searched for the problem, there was this blog post which I tried to implement but my case is a different than the one in the blog post in these items:
He faces the exception when tries to update (while I try to insert).
The tables architecture is different.
how can I solve this problem?
Here's the insertion code:
Employee emp = new Employee();
emp.Name = empName; // empName is a local variable
// What should I default emp.Orders to?
dc.Employees.InsertOnSubmit(emp);
dc.SubmitChanges();
P.S: My DataContext is defined on class-level in my repository and the exception is being thrown when I call dc.SubmitChanges();. and I didn't Attach any object why does it say that?
Here is an article explaining what you need to do using the Attach and Detach methods:
http://www.codeproject.com/KB/linq/linq-to-sql-detach.aspx
I am guessing it is trying to save something else besides just the employee object or you aren't showing us the full code in your repository. When you instantiate your DataContext object (dc) try setting DeferredLoadingEnabled = false, and ObjectTrackingEnabled = false and see if it works. If it does, try watching the SQL code in SQL Server Profiler and see if it is modifying other objects that may have came from a different context like the message says.
var dc = new MyDataContext()
{
DeferredLoadingEnabled = false,
ObjectTrackingEnabled = false
};
My bet is on the primary key.
Are you sure the primary key is also set on auto increment?
Did you
try changing the name, does it work then?
What happens if you remove
all rows from your DB? can you insert one then?

Resources