how to retrieve entity on update in dynamics crm 2011 - plugins

I am new to CRM and trying to write a plugin.
It's should be simple, but it's not.
For some reason I can't retrieve entity.
I know for sure that it is exists in database and ID is correct.
The code below....
Does anyone has any ideas why it is not working?
Thanks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using System.ServiceModel;
using Microsoft.Xrm.Sdk.Query;
using System.Collections;
namespace Copy_field
{
public class Copy_field : IPlugin
{
/// <summary>
/// A plugin copyies fields from Contact Entity to Case Entity. This allows display
/// information about the client on case Entity and change it directly from Case Entity
/// </summary>
/// <remarks>Register this plug-in on the Create case, update case and update of contact
/// </remarks>
///
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext));
ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
Entity entity;
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "incident") { return; }
}
else
{
return;
}
// tracer.Trace("1. THIS IS an/a: " + entity.LogicalName);
// tracer.Trace("2. Id: " + entity.Id);
// tracer.Trace("2.2 output parametersId: " + context.OutputParameters["id"].ToString());
// if record exists - retrieve the entity
///////////////////////////////////////////////////////////////////
ColumnSet cols = new ColumnSet(true);
Entity yahhooo = service.Retrieve(entity.LogicalName, entity.Id, cols);
}
}
}

don't forget that in update message , you only access to filed's that you update(change) it...
you can write as in the following method to trace your code(line to line)
public static void LogFile(string log)
{
try
{
TextWriter tw = new StreamWriter(#"C:\Inetpub\wwwroot\inventorylog_" + Guid.NewGuid() + ".txt");
tw.Write(log);
tw.Close();
}
catch
{
}
}
Be successful

Well, you could give us a little bit more of information about it like, is it throwing any exception? My guess is that you are getting the following error:
"The "yourentity" with id "yourentityid" does not exist in the database", if so you may be trying to retrieve a record on it's create on Pre-Operation pipeline.
Anyway, help us help you giving us more information.

Related

Attaching Entity to context fails because it already exist

I use the Unity of Work and Generic Repository of CodeCamper.
to update an entity, the generic repo has:
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
the web api method:
public HttpResponseMessage Put(MyEditModel editModel)
{
var model = editModel.MapToMyEntity();
_myManager.Update(model);
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
The Update method:
public void Update(MyEntity model)
{
Uow.MyEntities.Update(model);
Uow.Commit();
}
In the Unityof Work:
IRepository<MyEntity> MyEntities { get; }
When updating an entity I get the following error:
Additional information: Attaching an entity of type 'X' 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.
The update works fine, when it is the first method you call of the repository.
(I created an entity with an id already in the DB and called the Update.)
The update doesn't work when you do a get of the entity before you update it.
(For example, I get an entity X, convert it to a DTO, then change some values in the UI,
then call a web api that creates an entity X with the new values and
call the Update of the repository.)
Any ideas to avoid this?
When you have a CRUD app, you always call the get before the update.
I'm using my own attach method:
public void Attach<E>(ref E entity)
{
if (entity == null)
{
return;
}
try
{
ObjectStateEntry entry;
bool attach = false;
if (ObjectStateManager.TryGetObjectStateEntry(CreateEntityKey(entitySetName, entity), out entry))
{
attach = entry.State == EntityState.Detached;
E existingEntityInCache = (E)entry.Entity;
if (!existingEntityInCache.Equals(entity))
{
existingEntityInCache.SetAllPropertiesFromEntity(entity);
}
entity = existingEntityInCache;
}
else
{
attach = true;
}
if (attach)
objectContext.AttachTo(entitySetName, entity);
}
catch (Exception ex)
{
throw new Exception("...");
}
}
I had the same issue. The problem was in mixed contexts. When you read entity from DB in context1. Then if you can update this entity with contex2 (other instance of the same context with own entity cache). This may throw an exception.
Pls check for references too:
by context1:
read entity1 with referenced entity2 from DB
by context2:
read entity2 from DB. Then update entity1 (with referenced entity2 from context1).
When you try attach entity1 with referenced entity2 to context2, this throw exception because entity2 already exists in context2.
The solution is use only one context for this operation.

DbContext does not contain a definition for 'Connection' error using transaction Entity Framework

I need to use a transaction in Entity Framewok (version 5) in a controller of an MVC4 project.
This because I've to save data in different table within the same transaction and avoid data inconsistency..
using System;
using System.Collections.Generic;
using System.Linq; using System.Web.Mvc;
using System.IO;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Data;
using System.Data.Objects;
private DBcontextName context = new DBcontextName ();
context.Connection.Open();
When i try to use transaction, the object Connection is not recognized by context
DbContext does not contain a definition for 'Connection' and no extension method 'Connection' accepting a first argument of type...
I don't understand what it's wrong,
can you help me please?
namespace NameSpaceName {
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
public partial class DBcontextName : DbContext
{
public DBcontextName ()
: base("name=DBcontextName ")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet......{ get; set; }
public DbSet......{ get; set; }
}
}
Thanks
Try like this:
using (TransactionScope scope = new TransactionScope())
{
using (DBcontextName context = new DBcontextName()
{
SqlConnection connection = (SqlConnection)((EntityConnection)context.ObjectContext.Connection).StoreConnection;
using (SqlCommand command = storeConnection.CreateCommand())
{
command.Connection = connection ;
connection.Open();
command.CommandText = yourStoredProcedureName;
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(yourSqlParameters);
using (DbDataReader reader = command.ExecuteReader())
{
// Do stuff
}
}
}
scope.Complete();
}
You only need to do this if you are calling a stored procedure though (for speed with multiple records, you could have a proc taking a table-valued parameter to save a list of records). If you just want to use entity framework, you can do this:
using (TransactionScope scope = new TransactionScope())
{
using (DBcontextName context = new DBcontextName()
{
// Get objects, delete objects, add objects, etc.
// Or add new objects
context.SaveChanges();
}
scope.Complete();
}

Getting the entity mapped table name using T4

I am trying to use T4 to generate code for the following:
public virtual IList<Frequency> GetAll()
{
using (var wc = new WCDataClassesDataContext())
{
return wc.Frequencies.ToList();
}
}
public virtual IList<Frequency> GetAll(Expression<Func<Frequency, bool>> whereClause)
{
using (var wc = new WCDataClassesDataContext())
{
return wc.Frequencies.Where(whereClause).ToList();
}
}
In T4 i am using:
foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
{
fileManager.StartNewFile(entity.Name + "BaseFinder.cs");
BeginNamespace(code);
#>
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.Linq;
using System.Linq.Expressions;
<#=codeStringGenerator.EntityClassOpening(entity)#>
{
public virtual IList<<#=entity.Name #>> GetAll()
{
using (var wc = new WCDataClassesDataContext())
{
return wc.[[Frequencies]].ToList();
}
}
public virtual IList<<#=entity.Name #>> GetAll(Expression<Func<<#=entity.Name #>, bool>> whereClause)
{
using (var wc = new WCDataClassesDataContext())
{
return wc.[[Frequencies]].Where(whereClause).ToList();
}
}
......
}
Instead of [[Frequencies]] i want the main table name that the entity is mapped to.
I am trying to setup various getters which can be used easily in the classes.
Could you tell me what is the solution to do this, or there could be some other way to do this?
Hope you got my point.
Thanks.
It looks like you have the entity type already, so I think you're close - all you need to do is get the navigation properties that have a relationship multiplicity of many, and you should be set.
Something like:
EntityType et = entity.GetType();
foreach(var navProp in et.NavigationProperties.Where(np=>np.DeclaringType == et
&& np.RelationshipMultiplicity == RelationshipMultiplicity.Many))
{
string s = string.Format("public virtual IList<{0}> GetAll() ...",
navProp.ToEndMember.GetEntityType().Name);
}
The Entity Framework DB-first generator already does a flavor of this; if you go digging around under the EDMX, you should see a *.Context.tt or something similar. In there, do a search for NavigationProperty, there is a code string helper method to generate something similar.

Readonly properties in EF 4.1

I've faced with situation when I need to have EF readonly property in case of 'optimistic update'(you do not load current state of your domain object from database to check what properties are really changed. You just set your object as Modified and update it to database. You avoid redundant select and merge operations in this case).
You can't write something like this : DataContext.Entry(entity).Property(propertyName).IsModified = false;, because setting of 'false' value is not supported and you will get an exception. (in EF 4.1)
I've created a simple structure for registering readonly properties in repository.
So, you can easy Modify just nonreadonly properties.
What do you think about this?
public abstract class RepositoryBase<T> where T : class
{
private const string MethodReferenceErrorFormat = "Expression '{0}' refers to a method, not a property.";
private const string FieldReferenceErrorFormat = "Expression '{0}' refers to a field, not a property.";
protected IList<PropertyInfo> _readOnlyProperties;
/// <summary>
/// This method is used to register readonly property for Entity.
/// </summary>
/// <param name="propertyLambda">Entity property as LambdaExpression</param>
protected void RegisterReadOnlyProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda)
{
Guard.ArgumentNotNull(propertyLambda, "propertyLambda");
var propertyMember = propertyLambda.Body as MemberExpression;
if (propertyMember == null)
{
var exceptionMessage = string.Format(MethodReferenceErrorFormat, propertyLambda);
throw new ArgumentException(exceptionMessage);
}
var propertyInfo = propertyMember.Member as PropertyInfo;
if (propertyInfo == null)
{
var exceptionMessage = string.Format(FieldReferenceErrorFormat, propertyLambda);
throw new ArgumentException(exceptionMessage);
}
_readOnlyProperties.Add(propertyInfo);
}
/// <summary>
/// This method is used to attach domain object to DbContext and mark it as modified to save changes.
/// </summary>
/// <param name="entity">Detached entity</param>
public void SetModified(T entity)
{
Guard.ArgumentNotNull(entity, "entity");
//Mark whole entity as Modified, when collection of readonly properties is empty.
if(_readOnlyProperties.Count == 0)
{
DataContext.Entry(entity).State = EntityState.Modified;
return;
}
//Attach entity to DbContext.
_dbSet.Attach(entity);
//Mark all properties except readonly as Modified.
var allProperties = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
var propertiesForUpdate = allProperties.Except(_readOnlyProperties);
foreach (var propertyInfo in propertiesForUpdate)
{
DataContext.Entry(entity).Property(propertyInfo.Name).IsModified = true;
}
}
This would work but I don't like the need to register modified properties directly in repository. You can forget about registered properties and code will accidentaly not save some changes - that will be bug which will be hard to find when reusing repository in complex scenarios. I like explicit definition of updated properties each time you call something like Update on your repository. Also I don't like reflection in the code. Unless you modify your code to get reflected data about each entity only once for whole application you are doing it wrong.
I wrote the answer for EFv4 but it can be easily modified to EFv4.1:
public void Update(T entity, params Expression<Func<T, object>>[] properties)
{
_dbSet.Attach(entity);
DbEntityEntry<T> entry = _context.Entry(entity);
foreach (var selector in properties)
{
entry.Property(selector).IsModified = true;
}
}
You will call it like:
repo.Update(entity, e => e.Name, e => e.Description);

EF4 CTP5 POCO Not Updating Navigation Property On Save

I'm using EF4 with POCO objects the 2 tables are as follows
Service
ServiceID,
Name,
StatusID
Status
StatusID,
Name
The POCO objects look like this
Service
ServiceID,
Status,
Name
Status
StatusID,
Name
With Status on the Service object being a Navigation Property and of type Status.
In my Service Repository I have a save method that takes a service objects attaches it to the context and calls save. This works fine for the service, but if the status for that service has been changed it does not get updated. My Save method looks like this
public static void SaveService(Service service)
{
using (var ctx = Context.CreateContext())
{
ctx.AttachModify("Services", service);
ctx.AttachTo("Statuses",service.Status);
ctx.SaveChanges();
}
}
The AttachModify method attaches an object to the context and sets it to modified it looks like this
public void AttachModify(string entitySetName, object entity)
{
if (entity != null)
{
AttachTo(entitySetName, entity);
SetModified(entity);
}
}
public void SetModified(object entity)
{
ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
If I look at a SQL profile its not even including the navigation property in the update for the service table, it never touches the StatusID. Its driving me crazy. Any idea what I need to do to force the Navigation Property to update?
Edit
To give a quick example of the problem heres a quick console app that uses EF with my POCO objects to produce this issue
static void Main(string[] args)
{
Service svc = GetService();
Console.WriteLine("Service : " + svc.Name + " , Status : " + svc.Status.Name);
//Change and save Status
svc.Status = GetStatus("Stopped");
using (var ctx = new TestEFContext())
{
//Status is changed
Console.WriteLine("Service : " + svc.Name + " , Status : " + svc.Status.Name);
ctx.AttachModify("Services", svc);
ctx.AttachTo("Statuses", svc.Status);
ctx.SaveChanges();
}
//Re-fetch service from db and check status
svc = GetService();
//Status is set back to its old value!!!!!!!!
Console.WriteLine("Service : " + svc.Name + " , Status : " + svc.Status.Name);
Console.ReadLine();
}
private static Service GetService()
{
using (var ctx = new TestEFContext())
{
return ctx.Services.Include("Status").FirstOrDefault();
}
}
private static Status GetStatus(string name)
{
using (var ctx = new TestEFContext())
{
return ctx.Statuses.Where(n=>n.Name == name).FirstOrDefault();
}
}
public class Service
{
[DataMember] public int ServiceID { get; set; }
[DataMember] public string Name { get; set; }
[DataMember] public Status Status { get; set; }
}
public class Status
{
[DataMember] public int StatusID { get; set; }
[DataMember] public string Name { get; set; }
}
The reason I'm not holding on to the context is because in the real app I'm trying to use this on its all done in WCF in a disconnected way.
This problem was dragging on so I ended up going for a solution I'm not overlly happy with but I just needed to get it working.
My solution was on save to re-fetch the entities from the DB and use ApplyCurrentValues to update them to match the updated POCO objects.
Based on my example in the question this is the solution I used
static void Main(string[] args)
{
Service svc = GetService();
svc.Status = GetStatus("Stopped");
using (var ctx = new TestEFContext())
{
var svc2 = ctx.Services.Where(s=>s.ServiceID == svc.ServiceID).FirstOrDefault();
svc2.Status = ctx.Statuses.Where(n => n.StatusID == svc.Status.StatusID).FirstOrDefault();
ctx.ApplyCurrentValues("Services", svc);
ctx.SaveChanges();
}
}
I really would rather get it working the way it was coded in the question as I think that is a much neater solution so if anyone can improve on this please do
You must manually set state to Modified for each entity you want to update. Attaching entity to context set its state to Unchanged. Also you don't need to attach status separately. It is already attached with service because AttachTo method attaches whole object graph. You can also try to use Attach instead of AttachTo but I don't think it will be source of the problem.