im new in CRM. I have create two entity : Order and Product. On order entity there is look up field that fire to product entity. I try to get productquantity from product through look up field and paste it to a field within the order entity. Here is the code i tried:
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.Attributes.Contains("new_productname"))
{
Entity productreference = service.Retrieve("new_callistyproduct", ((EntityReference)entity["new_productname"]).Id, new ColumnSet(true));
if (productreference.Attributes.Contains("new_productquantity"))
{
if (entity.Attributes.Contains("new_numberofproduct"))
entity["new_numberofproduct"] = productreference.GetAttributeValue<Decimal>("new_productquantity");
else
entity.Attributes.Add("new_numberofproduct", productreference.GetAttributeValue<Decimal>("new_productquantity"));
}
}
}
I want this plugin work whenever i create a new record. So i register this plugin as Pre-create event. But, when i try to create a record. This plugin did't retrieve value from productquantity field.
So, i tried to run this plugin as Pre-Update event. On the record i've create before, i change the lookup value from product A to product B. And its work, the plugin retrieve a product quantity value from product B.
The question is, what should i do if i want this plugin also work for pre-Create event.
Thanks
If you want to update a target entity, and have CRM perform the update for you, you'll have to register your plugin on the Pre-Create or Pre-Update. If you want to do the action on a Post event, you'll need to call Update using the IOrganizationService, just updating the Target won't work. You'll also want to be sure you don't create an infinite loop, where an update triggers the plugin, which performs another update that triggers the same plugin, which performs another update... etc. etc.
Related
I am creating a new contact record and I need to set lastusedincampaign field while creating. But my entity is being created with empty lastusedincampaign field.
I only can set it programatically with Update method after Create.
Where the problem can be?
P.S.: Creating and then updating my entity record is not a good idea, cause I have about 4k entity records to create at once.
UPDATE 1 (test code):
Entity contact = new Entity("contact");
contact["fullname"] = "New contact";
contact["lastusedincampaign"] = DateTime.UtcNow;
CrmHelper.InitializeCrmService().Create(contact);
Looks like CRM ignores lastusedincampaign attribute like it does a few other during create operation. If you do not want to perform create/update operations at the same time, why don't you create a temporary workflow that would run asynchronously and update the field's value? This way async server takes most of the load and the record creations are faster.
Side note 4k records is not an awfully lot of records to perform a create/update simultaneously, I have worked with records in the tens of thousands and CRM never bottle necked on me.
The behavior you described is expected. If you check the Metadata for the attribute lastusedincampaign you will find that the field has IsValidForCreate set to false and IsValidForUpdate set to true.
You must update the record after you create it if you want to fill that field.
I am using Entity framework and I have Users, Events and a table UsersEvents.
I know to this questions I probably can find on google, and I already tried but somehow, still have problems.
So I have:
User: UserId, Name
Event: EventId, Title
UserEvents: UserId, EventId
I want to create Event.
So on my Repository I have a method:
public void CreateEvent(Event #event)
{
//How to add event? (so the database will update the user that created the
//event and also will update the UsersEvents table.
}
I have tried to add the event first, but then had a problem to get the user.
Can someone help me and even without a code, just to help me understand how should I do this. Should I add the event and then the user? or should I add the event and the user to the UsersEvents? Thanks in advance :)
In a pure many to many association (where the junction table is not visible in the class model) you have to add items to the collection of the owner. In your case this would be:
var evnt = new Event { ... };
var user = db.Users.Include(u => u.Events).Single(u => u.UserId == id);
user.Events.Add(evnt);
db.SaveChanges();
The Include is there to make sure that user.Events is loaded before you add an item to it. If it isn't loaded the change tracker won't notice the change and nothing is saved.
But I think I understand your problem. You've implemented a repository pattern, so you feel forced to handle each object by its own repository. A User has nothing to do with an EventRepository, right? So remove this repository layer! In most cases it's just a useless layer that only sandbags everything you want to do with data. To get convinced you may want to read Generic Repository With EF 4.1 what is the point.
I have a little problem and I need your help with it. I'm using Entity Framework for database handling and I want to update a dataset in this database.
I have an EntityObject with all the changes and want to be able to update this Object with existing Object.
I'm using the following code to update the data:
IQueryable<Competitors> getCompetitor = DatabaseObject.Competitors.Where(SelectOnly => SelectOnly.competitorID == competitorObject.competitorID);
Competitors competitor = getCompetitor.First();
competitor = competitorObject;
DatabaseObject.SaveChanges();
But this deosn't work. How can I update the date in database?
Assuming, that your competitorObject is of Competitors type (competitor = competitorObject), you have to attach it to your context, mark it as modified, and then save changes:
DatabaseObject.Competitors.Attach(competitorObject);
DatabaseObject.Entry(competitorObject).State = EntityState.Modified;
DatabaseObject.SaveChanges();
There's no need to retrieve source object in your case, but without attaching, the context knows nothing about your updated object.
The piece of code, which is marking an object as modified, can be a little different, if you're using ObjectContext API instead of DbContext API:
DatabaseObject.ObjectStateManager.GetObjectStateEntry(competitorObject).SetModified();
The only change you need to make to your code to get it to work is update at least one property on the fetched entity. You are updating the reference, not the property values so like this:
IQueryable<Competitors> getCompetitor = DatabaseObject.Competitors.Where(SelectOnly => SelectOnly.competitorID == competitorObject.competitorID);
Competitors competitor = getCompetitor.First();
competitor.Name = competitorObject.Name;
competitor.Contact = competitorObject.Contact;
DatabaseObject.SaveChanges();
Or as Dennis has said you can attach the CompetitorObject to the context and mark it as modified. Doing it that way will override all the properties of the existing Competitors record with the values of CompetitorObject.
Okay, so it's late and I'm tired, but this shouldn't be happening... or so I believe. I have the following code for an event handler for a button click where I create a new customer from a web form.
int customerId = <from_somewhere_doesnt_matter>;
Customer cust;
if (int.TryParse(Request.QueryString["cid"], out customerId)) {
// update existing customer
cus = db.Customers.Single(c => c.CustomerId == customerId);
cus.UpdatedByUser = user;
cus.Updated = DateTime.Now;
}
else {
// create new customer
cus = new Customer();
cus.InsertedByUser = user;
cus.Inserted = DateTime.Now;
}
SetFields(cus);
db.SaveChanges();
The SetFields() method just populates the different properties for the customer from the corresponding web form fields.
I have been running this code in production for quite a while and it's been working fine. However, recently a user told me it doesn't work to add a new user (doesn't happen very often). I checked it, and sure enough, I filled in the form and tried to add the user but was just redirected back to the user list without any error message and without a new user.
I checked the code, and realised I had forgotten to add the db.Users.AddObject(usr) when adding a new user. I added the method call, and the user was added correctly. I then went to the customer code, just to check how and when I call the AddObject-method there, and it turns out I don't!
I might be blind, but I have searched the source code and I do not call the method anywhere and it still works to add a customer! The only thing I can think of is that the customer is added because it refers to another object (the current user), and that somehow triggers an add. The user does not depend on any other fields.
What is happening!?
Thanks in advance!
The reason might be automatic association fixup. The T4 Template POCO Generator of EF 4.0 for instance creates such methods which are called in the property setters. Possibly it happens in this line in your code:
cus.InsertedByUser = user;
If your User entity has a collection of customers (as the inverse navigation property to InsertedByUser) then the POCO Generator would create a fixup method which does something like ...
InsertedByUser.Customers.Add(this);
... where this is cus in your example. This is called in the setter for the InsertedByUser property. This means that your new created customer cus is automatically added to the Customers collection of the user which you assign. EF change detection will recognize this and put the new customer in Added state into the context. When you call SaveChanges a new customer record in the database is created.
Just a hypothesis. You could check in detail what's going on by debugging into the property setter.
When you set
cus.InsertedByUser = user;
Your customer will be added to the user.Customers collection that represents the other end of the many-to-one. This gives EF a handle on the object which will then be added to the context and saved away since it is new.
I have the following scenario:
Entities are loaded from the database.
One of them is presented to the user in a Form (a WPF UserControl) where the user can edit properties of that entity.
The user can decide to apply the changes to the entity or to cancel the editing.
How would I implement something like this with the EntityFramework?
My problem is that, when I bind the UI directly to the Properties of the Entity, every change is instantanously applied to the entity. I want to delay that to the moment where the user presses OK and the entity is validated successfully.
I thought about loading the Entities with NoTracking and calling ApplyPropertyChanges after the detached entity has been validated, but I'm not entirely sure about the correct way to do that. The docu of the EntityFramework at MSDN is very sparse.
Another way I could think of is to Refresh the entity with StoreWins, but I don't like resetting the changes at Cancel instead of applying changes at Ok.
Has anyone a good tutorial or sample?
One options is what you said do a no-tracking query.
ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First(c => c.ID == 232);
Then the customer can modify 'customer' as required in memory, and nothing is actually happening in the context.
Now when you want actually make the change you can do this:
// get the value from the database
var original = ctx.Customers.First(c => c.ID == customer.ID);
// copy values from the changed entity onto the original.
ctx.ApplyPropertyChanges(customer); .
ctx.SaveChanges();
Now if you are uncomfortable with the query either for performance or concurrency reasons, you could add a new extension method AttachAsModified(...) to ObjectContext.
that looks something like this:
public static void AttachAsModified<T>(
this ObjectContext ctx,
string entitySet,
T entity)
{
ctx.AttachTo(entitySet, entity);
ObjectStateEntry entry =
ctx.ObjectStateManager.GetObjectStateEntry(entity);
// get all the property names
var propertyNames =
from s in entry.CurrentValues.DataRecordInfo.FieldMetadata
select s.FieldType.Name;
// mark every property as modified
foreach(var propertyName in propertyNames)
{
entry.SetModifiedProperty(propertyName);
}
}
Now you can write code like this:
ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First();
// make changes to the customer in the form
ctx.AttachAsModified("Customers", customer);
ctx.SaveChanges();
And now you have no concurrency or extranous queries.
The only problem now is dealing with FK properties. You should probably look at my index of tips for help here: http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx
Hope this helps
Alex
I suggest IEditableObject, too, and additionally IDataErrorInfo.
The way i do it is, i basically have a viewmodel for an entity that takes the entity as constructor parameter (basically a wrapper object).
In BeginEdit, i copy the entity properties to my viewmodel, so if i do CancelEdit, the data is only changed in the ViewModel and the original Entity hasn't changed. In EndEdit, i just apply the ViewModel properties to the Entity again, or course only if validation has succeeded.
For validation i use the methods of IDataErrorInfo. I just implement IDataErrorInfo.Error so that it checks each Property name via IDataErrorInfo[string columnName] and concatenates eventual error messages. If it's empty, everything is ok. (not sure if Error is meant to be used that way, but i do it)
If i have other Entities attached to my original Entity, such as Customer.Orders, i create them as nested ViewModels in the original Entity's ViewModel. The original ViewModel calls it's subModels' Begin-,Cancel-,EndEdit / Error methods in it's own implementations of those methods then.
It's a bit more work, but i think it's worth it because between BeginEdit and EndEdit, you can be pretty sure that nothing changes without you noticing it. And having a code snippet for INotifyPropertyChanged-enabled properties helps a lot, too.
The normal way of doing this is binding to something that implements IEditableObject. If and how that fits in with the entity framework, I'm not sure.