Comparing, Adding, and Updating date field in an entity - c#

Trying to compare an existing date from an entity with current date. If entity field (testfield) of entity (testentity) date is equal to OR after current date, then add 1 year to the date in the field.
Issue - For some reason, its reading all the dates and comparing as well but not updating it in the field. I have used post operation step on the entity.
Update: I added ServiceContext.UpdateObject(entity) and ServiceContext.SaveChanges(); to the code but now its giving me "The context is not currently tracking..." error.
Any help would be deeply appreciated. Thanks!
Please take a look at following code.
public class PostUpdate: Plugin
{
public PostUpdate()
: base(typeof(PostUpdate))
{
base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(40, "Update", "new_testentity", new Action<LocalPluginContext>(ExecutePostUpdate)));
protected void ExecutePostupdate(LocalPluginContext localContext)
{
// get the plugin context
IPluginExecutionContext context = localContext.PluginExecutionContext;
//Get the IOrganizationService
IOrganizationService service = localContext.OrganizationService;
//create the service context
var ServiceContext = new OrganizationServiceContext(service);
ITracingService tracingService = localContext.TracingService;
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parmameters.
Entity entity = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an account.
// If not, this plug-in was not registered correctly.
if (entity.LogicalName != "new_testentity")
return;
try
{
var k = entity["new_testfield"];
DateTime m = Convert.ToDateTime(k);
DateTime d = DateTime.Now;
int result = DateTime.Compare(m, d);
// compare the dates
if (result <= 0)
{
try
{
entity["new_testfield"] = DateTime.Now.AddYears(1);
ServiceContext.UpdateObject(entity);
}
ServiceContext.SaveChanges();
//Adding this is giving me "The context is not currently tracking the 'new_testentity' entity."
}
catch (FaultException<OrganizationServiceFault> ex)
{
}
}
}
//<snippetFollowupPlugin3>
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in the FollupupPlugin plug-in.", ex);
}
//</snippetFollowupPlugin3>
catch (Exception ex)
{
tracingService.Trace("FollowupPlugin: {0}", ex.ToString());
throw;
}
}
}

You should register your plugin on the pre-operation step then simply add/change the appropriate value in the InputParameter PropertyBag. That way your changes are inline with the transaction and you don't need a separate update call.

Try attaching your entity to the serviceContext.
http://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.client.organizationservicecontext.attach.aspx

Related

EF Core Same TABLE TWO ACTIONS (Remove item + update remaining ones)

I have a weird situation.
I have a list from where I need to remove an item from the DB, then all remaining ones I need to just increment and update them.
I use.AsNoTracking() on the list filtering but I cannot perform the above actions thought.
Keeps telling me that "
"The property 'ListNumber' on entity type 'LIST' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key first delete the dependent and invoke 'SaveChanges' then associate the dependent with the new principal."
I've tried also to build 1 method for remove and 1 for update the remaining items and call them from the controller (the first one is the remove then the second one is the update) but the same result.
Anyone can help me out because I'm stuck I would highly appreciate a clear example or approach on how I can deal with the above situation.
Thank you in advance.
This is how I call the methods from the controller
await _repo.RemoveFromList("1234", "1");
await _repo.ResetList("1234");
Below are the methods I'm using, remove one works but when I'm using the reset list I got an exception
public async Task RemoveFromList(string listNumber, string listItem)
{
try
{
var entity = await _context.LIST.Where(x => x.ListNumber == listNumber && x.ListItem == listItem).FirstOrDefaultAsync();
_context.LIST.Remove(entity);
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
throw;
}
}
public async Task ResetList(string listNumber)
{
try
{
var entities = await _context.LIST.AsQueryable().Where(x => ListNumber== listNumber).ToListAsync();
var startFrom = 1;
foreach (var en in entities)
{
en.NewListNumber = startFrom.ToString().PadLeft(3, '0');
startFrom++;
_context.LIST.Update(en);
}
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
throw;
}
}

Retrieve triggering an update in plugin

I've got a plugin on Update (pre-op) of InvoiceDetail, in which I'm retrieving the associated Invoice to get some more information from it (ie: the tax profile that was selected at the invoice level) in CRM 2016.
Here's how I do it:
//xrmObjects is an object containing all useful objects in plugins/workflow...
var invoice = RetrieveEntity(xrmObjects.Service, xrmObjects.TracingService, image["invoiceid"] as EntityReference, new ColumnSet("invoiceid", "pricelevelid", "customerid", "opportunityid", "xtc_tax_definition"));
This specific line of code above triggers another Update on InvoiceDetail
Here's the method invoked above:
public static Entity RetrieveEntity(IOrganizationService service, ITracingService tracingService, EntityReference target, ColumnSet columnSet)
{
Entity entity = new Entity();
try
{
entity = CrmServiceExtensions.ExecuteWithRetry<RetrieveResponse>(service, new RetrieveRequest
{
Target = target,
ColumnSet = columnSet
}).Entity;
}
catch (Exception ex)
{
tracingService.Trace($"Error retrieving {target.LogicalName}: {ex.Message}");
throw;
}
return entity;
}
Here's ExecuteWithRetry:
public static T ExecuteWithRetry<T>(IOrganizationService service, OrganizationRequest request)
where T : OrganizationResponse
{
T response = null;
int i = 0;
// Maximum of five iterations.
while (i < 5)
{
try
{
response = (T)service.Execute(request);
// If the Execute does not throw an Exception, break the loop
break;
}
catch (System.Web.Services.Protocols.SoapException e)
{
// Retry if the SoapException is a "Generic SQL Error",
// otherwise rethrow the SoapException.
// "Generic SQL Error" might indicate a deadlock.
if (e.Detail.InnerText.ToLower().Contains("generic sql error"))
{
++i;
// Wait (sleep thread) for i * 1000 milliseconds.
// So, first iteration waits 1 second,
// while fifth iteration will wait 5 seconds.
System.Threading.Thread.Sleep(i * 1000);
}
else throw;
}
}
if (i >= 5)
{
throw new Exception("ExecuteWithRetry: too many retries");
}
return response;
}
I have validated that nothing funky is happening, the update message on InvoiceDetail is triggered again at the line response = (T)service.Execute(request);
I also tried by using early-bound and a context to retrieve the invoice but the LoadProperty methods which loads the invoice does the same thing....
using (XrmServiceContext ctx = new XrmServiceContext(xrmObjects.Service))
{
Xrm.InvoiceDetail image = xrmObjects.PluginContext.PreEntityImages["invoicedetail"].ToEntity<Xrm.InvoiceDetail>();
try
{
ctx.LoadProperty(image, "invoice_details");
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException($"Error retrieving invoice details' invoice: {ex.Message}");
}
}
I can't see anything in my steps configuration that would do this. Any ideas?
Instead of using LoadProperty, I simply retrieved the invoice manually like so
var invoice = ctx.InvoiceSet.SingleOrDefault(x => x.Id == image.InvoiceId.Id);
Instead of:
ctx.LoadProperty(image, "invoice_details");
For some reason, LoadProperty is triggering unwanted update message on child invoice details...

savechanges() not saving?

I have this C# code:
public object guardardinerohoy(float dinero,string comentario)
{
object dineromov1 = this.nuevodineromovimiento(dinero, variablesestaticas.usuarioglobal, DateTime.Now, null, claseenumeraciones.enumdineromovimiento.iniciosistema, comentario, DateTime .Now );
object resultado = "ok";
string abrirconexion = Conexion.conexion.abrirconexion();
if (dineromov1.GetType() != "".GetType() && abrirconexion == "ok")
try
{
Conexion.conexion.conect.AddTodineromovimiento((dineromovimiento)dineromov1);
Conexion.conexion.conect.SaveChanges();
return "ok";
}
catch (Exception ex)
{
resultado = ex.Message;
}
else
{
resultado = dineromov1.ToString() + abrirconexion;
return resultado;
}
}
I return "ok" if this saved successfully. Now when I checked if this was saved it was not. I do not understand why if it did not return an exception. This does not happen all the time. Sometimes it saves and sometime it does not.
I found this thread which says if it does not have exception, everything is ok.
Check if an insert or update was successful in Entity Framework
Entity Framework will throw an exception upon failure of Insert, Update or Delete.
Thus, you can assume with no exception that it's successful.

Nhibernate two transaction read the same table and insert the same table make one transaction fail

User Table structure
Id
Username (unique constrain)
I have the problem with Nhibernate and SqlServer like this.
There are two concurrent transactions trying to insert data in the User Table.
Both transactions query the data in table to check if the new Username to insert does not appear in the table.
The problem is that let say.
Transaction1 and Transaction2 read User Table and found that there is no username embarus in User Table.
Then Transaction2 trying to insert embarus in User table while Transaction1 has been inserted and committed embarus in table already.
Therefore Transaction2 get exception for unique constrain.
Please help me to solve this problem, any ideas or article that may be useful.
I found that SqlServer 2008 uses ReadCommitted for default transaction isolation level.
Thank you so much.
You need to catch and handle the unique constraint violation. The best way to do that is to create an ISqlExceptionConverter implementation to translate the RDBMS specific exception to a custom exception in your application.
public class SqlServerExceptionConverter : ISQLExceptionConverter
{
public Exception Convert(AdoExceptionContextInfo adoExceptionContextInfo)
{
var sqlException = adoExceptionContextInfo.SqlException as SqlException;
if (sqlException != null)
{
// 2601 is unique key, 2627 is unique index; same thing:
// http://blog.sqlauthority.com/2007/04/26/sql-server-difference-between-unique-index-vs-unique-constraint/
if (sqlException.Number == 2601 || sqlException.Number == 2627)
{
return new UniqueKeyException(sqlException.Message, sqlException);
}
}
return adoExceptionContextInfo.SqlException;
}
}
public class UniqueKeyException : Exception
{
public UniqueKeyException(string message, Exception innerException)
: base(message, innerException)
{ }
}
Usage:
using (var txn = _session.BeginTransaction())
{
try
{
var user= new User
{
Name = "embarus"
};
_session.Save(user);
txn.Commit();
}
catch (UniqueKeyException)
{
txn.Rollback();
var msg = string.Format("A user named '{0}' already exists, please enter a different name or cancel.", "embarus");
// Do something useful
}
catch (Exception ex)
{
if (txn.IsActive)
{
txn.Rollback();
}
throw;
}
}
Note that you should not reuse the session after the exception occurs.

Get specific element that throws exception

So let's say that I need to update a list of objects.
using(db)
{
repository = new Repository<Publication>(db);
foreach (KeyValuePair<int,int> item in publications)
{
Publication publication = repository.GetById(item.Key);
if (publication != null)
{
publication.Quantity = publication.Quantity - item.Value;
if (publication.Quantity > 0)
db.Publication.Attach(publication);
}
}
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException e)
{
throw new Exception("Could not update the database", e);
}
}
}
When I tried to save all the objects, if someone fails, it should be in the catch block, but my question is: how can I get the specific object that throws the exception?
You're catching DbUpdateConcurrencyException, which has an Entries property, documented as:
Gets DbEntityEntry objects that represent the entities that could not be saved to the database.
So basically that gives you all the problematic ones.

Categories