I have an Asp.Net MVC 5 using Entity Framework 6. I am using Unity.MVC5 Version 1.2.3.0
The issue I am having is that I would get the following error on certain scenarios when saving to the database
Additional information: The operation failed: The relationship could
not be changed because one or more of the foreign-key properties is
non-nullable. When a change is made to a relationship, the related
foreign-key property is set to a null value. If the foreign-key does
not support null values, a new relationship must be defined, the
foreign-key property must be assigned another non-null value, or the
unrelated object must be deleted.
After troubleshooting the issue I believe it has to do with how I have Unity.MVC5 configured. Here is my Unity.Config.cs
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterTypes(AllClasses.FromLoadedAssemblies(), WithMappings.FromMatchingInterface, WithName.Default);
container.RegisterType<IUnitOfWork, UnitOfWork>(new InjectionConstructor(new MasterContext()));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
So my controller would have something like this
private IService _Service;
MyController(IService service)
{
_Service = service;
}
However it looks like the data is not refreshing, Although when I use a SQL Profiler , it shows as it is making a call but the data is not refreshed as I do a breakpoint it still has old data. If I do away with the Unity.MVC injecting the classes, then the data gets refreshed and savechanges works fine.
I am overwriting the EF Context SaveChanges , here is the code
public override int SaveChanges()
{
var autoDetectChanges = Configuration.AutoDetectChangesEnabled;
try
{
Configuration.AutoDetectChangesEnabled = false;
ChangeTracker.DetectChanges();
var errors = GetValidationErrors().ToList();
if (errors.Any())
{
throw new DbEntityValidationException("Validation errors found during save.", errors);
}
//For modified column
var changedInfo = ChangeTracker.Entries().Where(t => t.State == EntityState.Modified)
.Select(t => new
{
Original = t.OriginalValues.PropertyNames.ToDictionary(pn => pn, pn => t.OriginalValues[pn]),
Current = t.CurrentValues.PropertyNames.ToDictionary(pn => pn, pn => t.CurrentValues[pn]),
objectContext = ((IObjectContextAdapter)this).ObjectContext,
ent = t,
});
foreach (var item in changedInfo)
{
if (GetTableInformation.GetTableName(item.objectContext, item.ent) != "HistoryLogs")
{
var result = GetDifference.GetChangedValues(item.Original, item.Current, item.objectContext, item.ent);
HistoryLog history = new HistoryLog();
history.Description = result[0];
history.TableFields = result[1];
history.UserId = userId;
history.TableAction = "Modified";
history.PrimaryKeyValue = Convert.ToInt32(result[2]);
history.TableName = result[3];
if (history.TableName == "MainRates")
{
MainRate rate = MainRates.SingleOrDefault(r => r.RateId == history.PrimaryKeyValue);
history.InstitutionId = rate.InstitutionId;
}
else if (history.TableName == "ProgramRates")
{
ProgramRate rate = ProgramRates.SingleOrDefault(r => r.RateId == history.PrimaryKeyValue);
history.InstitutionId = rate.InstitutionId;
}
else
{
int institutiondId;
if (int.TryParse(result[4], out institutiondId))
{
history.InstitutionId = institutiondId;
}
else
{
history.InstitutionId = null;
}
}
//InstitutionName and OPEID are being updated by trigger(executer after each insert operations)
//Check if there is any modified column or not
if (!string.IsNullOrEmpty(history.TableFields))
HistoryLogs.Add(history);
}
}
//For Deleted columns
var deletedInfo = ChangeTracker.Entries().Where(t => t.State == EntityState.Deleted)
.Select(t => new
{
Original = t.OriginalValues.PropertyNames.ToDictionary(pn => pn, pn => t.OriginalValues[pn]),
objectContext = ((IObjectContextAdapter)this).ObjectContext,
ent = t,
});
foreach (var item in deletedInfo)
{
if (GetTableInformation.GetTableName(item.objectContext, item.ent) != "HistoryLogs")
{
var result = GetDifference.GetDeletedValues(item.Original, item.objectContext, item.ent);
HistoryLog history = new HistoryLog();
history.Description = result[0];
history.TableFields = result[1];
history.UserId = userId;
history.TableAction = "Deleted";
history.PrimaryKeyValue = Convert.ToInt32(result[2]);
history.TableName = result[3];
if (history.TableName == "MainRates")
{
int locationRateId = (int)item.Original["LocationRateId"];
history.InstitutionId = LocationRates.SingleOrDefault(l => l.Id == locationRateId).InstitutionId;
}
else if (history.TableName == "ProgramRates")
{
ProgramRate rate = ProgramRates.SingleOrDefault(r => r.RateId == history.PrimaryKeyValue);
history.InstitutionId = rate.InstitutionId;
}
else
{
history.InstitutionId = result[4] == null ? null : (int?)int.Parse(result[4]);
}
//InstitutionName and OPEID are being updated by trigger(executer after each insert operations)
history.InstitutionName = "";
history.OpeidNumber = "";
//Check if there is any modified column or not
if (!string.IsNullOrEmpty(history.TableFields))
HistoryLogs.Add(history);
}
}
// For data that is added
string[] applicableTables = new string[] { "EligiblePrograms", "Fees", "LocationRates", "MainRates", "ProgramRates" };
var addedInfo = ChangeTracker.Entries().Where(t => t.State == EntityState.Added)
.Select(t => new
{
Current = t.CurrentValues.PropertyNames.ToDictionary(pn => pn, pn => t.CurrentValues[pn]),
ObjectContext = ((IObjectContextAdapter)this).ObjectContext,
Entity = t,
}).ToList();
//Placing this here adds the primary keys to the new values before saving their history.
Configuration.ValidateOnSaveEnabled = false;
int rVal = base.SaveChanges();
foreach (var item in addedInfo)
{
string tableName = GetTableInformation.GetTableName(item.ObjectContext, item.Entity);
if (applicableTables.Contains(tableName))
{
var result = GetDifference.GetDeletedValues(item.Current, item.ObjectContext, item.Entity);
HistoryLog history = new HistoryLog();
history.Description = result[0];
history.TableFields = result[1];
history.UserId = userId;
history.TableAction = "Added";
history.PrimaryKeyValue = Convert.ToInt32(result[2]);
history.TableName = result[3];
if (history.TableName == "MainRates")
{
history.InstitutionId = ((MainRate)item.Entity.Entity).InstitutionId;
}
else if (history.TableName == "ProgramRates")
{
history.InstitutionId = ((ProgramRate)item.Entity.Entity).InstitutionId;
}
else
{
history.InstitutionId = result[4] == null ? null : (int?)int.Parse(result[4]);
}
history.InstitutionName = "";
history.OpeidNumber = "";
//Check if there is any modified column or not
if (!string.IsNullOrEmpty(history.TableFields))
HistoryLogs.Add(history);
}
}
rVal += base.SaveChanges();
return rVal;
}
finally
{
Configuration.AutoDetectChangesEnabled = autoDetectChanges;
}
}
Then my Service class will do something like this:
Header header = _uow.MyRepository.GetByHeaderId(model.Id, model.HeaderId);
header.WebAddresses = string.Join(",", model.WebAddresses.ToArray());
header.Date = DateTime.Parse(model.Date);
header.IsField1 = model.Field1;
header.Field2 = model.Field2;
header.Field3 = model.Field3;
_uow.SaveChanges();
Related
I need to refactor the below code so that the deleted_at logic will be outside of the foreach (var app in data) loop. I tried to create the list guids and then add guids to it but its not working because model.resources is inside the loop and it is still deleting all the apps.
I need deleted_at logic outside because I'm trying to delete all apps which are in the database but are not in new data that I'm receiving from API.
If you have a better approach on my code I would love to see that, Thank you.
public async Task GetBuilds()
{
var data = new List<GetBuildTempClass>();
var guids = new List<GetBuildTempClass>();
using (var scope = _scopeFactory.CreateScope())
{
var _DBcontext = scope.ServiceProvider.GetRequiredService<PCFStatusContexts>();
foreach (var app in data)
{
var request = new HttpRequestMessage(HttpMethod.Get,
"apps/" + app.AppGuid + "/builds?per_page=200&order_by=updated_at");
var response = await _client_SB.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
BuildsClass.BuildsRootObject model =
JsonConvert.DeserializeObject<BuildsClass.BuildsRootObject>(json);
foreach (var item in model.resources)
{
var x = _DBcontext.Builds.FirstOrDefault(o =>
o.Guid == Guid.Parse(item.guid));
if (x == null)
{
_DBcontext.Builds.Add(new Builds
{
Guid = Guid.Parse(item.guid),
State = item.state,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Error = item.error,
CreatedByGuid = Guid.Parse(item.created_by.guid),
CreatedByName = item.created_by.name,
CreatedByEmail = item.created_by.email,
AppGuid = app.AppGuid,
AppName = app.AppName,
Foundation = 2,
Timestamp = DateTime.Now
});
}
else if (x.UpdatedAt != item.updated_at)
{
x.State = item.state;
x.UpdatedAt = item.updated_at;
x.Timestamp = DateTime.Now;
}
var sqlresult = new GetBuildTempClass
{
AppGuid = Guid.Parse(item.guid)
};
guids.Add(sqlresult);
}
//var guids = model.resources.Select(r => Guid.Parse(r.guid));
var builds = _DBcontext.Builds.Where(o =>
guids.Contains(o.Guid) == false &&
o.Foundation == 2 && o.DeletedAt == null);
foreach (var build_item in builds)
{
build_item.DeletedAt = DateTime.Now;
}
}
await _DBcontext.SaveChangesAsync();
}
}
I got it working I added var guids = new List < Guid > (); list to store data,
added guids.Add(Guid.Parse(item.guid)); to populate the list and finally wrote var builds = _DBcontext.Builds.Where(o = >guids.Contains(o.Guid) == false && o.Foundation == 2 && o.DeletedAt == null); outside the loop.
If anyone has a better suggestion please add a new answer.
public async Task GetBuilds() {
var data = new List < GetBuildTempClass > ();
var guids = new List < Guid > ();
using(var scope = _scopeFactory.CreateScope()) {
var _DBcontext = scope.ServiceProvider.GetRequiredService < PCFStatusContexts > ();
foreach(var app in data) {
var request = new HttpRequestMessage(HttpMethod.Get, "apps/" + app.AppGuid + "/builds?per_page=200&order_by=updated_at");
var response = await _client_SB.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
BuildsClass.BuildsRootObject model = JsonConvert.DeserializeObject < BuildsClass.BuildsRootObject > (json);
foreach(var item in model.resources) {
var x = _DBcontext.Builds.FirstOrDefault(o = >o.Guid == Guid.Parse(item.guid));
if (x == null) {
_DBcontext.Builds.Add(new Builds {
Guid = Guid.Parse(item.guid),
State = item.state,
CreatedAt = item.created_at,
UpdatedAt = item.updated_at,
Error = item.error,
CreatedByGuid = Guid.Parse(item.created_by.guid),
CreatedByName = item.created_by.name,
CreatedByEmail = item.created_by.email,
AppGuid = app.AppGuid,
AppName = app.AppName,
Foundation = 2,
Timestamp = DateTime.Now
});
}
else if (x.UpdatedAt != item.updated_at) {
x.State = item.state;
x.UpdatedAt = item.updated_at;
x.Timestamp = DateTime.Now;
}
guids.Add(Guid.Parse(item.guid));
}
}
var builds = _DBcontext.Builds.Where(o = >guids.Contains(o.Guid) == false && o.Foundation == 2 && o.DeletedAt == null);
foreach(var build_item in builds) {
build_item.DeletedAt = DateTime.Now;
}
await _DBcontext.SaveChangesAsync();
}
}
first I know this question has been asked but I really couldn't find an answer nor find the root of the problem so maybe a someone points me in the right direction.
I'm having the An entity object cannot be referenced by multiple instances of IEntityChangeTracker. error when trying to save into the log tables.
for the log table, I'm using
https://github.com/thepirat000/Audit.NET/tree/master/src/Audit.EntityFramework
so inside my DbContext class where I define the dbset, I have to override the onscopecreated function
the problem here is that when context.Savechanges run for the first audit record for each table it works but after first record, I get the multiple reference error.
so let's say I have the following tables
Languages table. with the following values
English,French,German
Countries Table with the following values
UK,France,Germany
for languages table, if I change English to English3 and save it works It records to the audit table but then for languages table, I can not do any changes at any records it's the same in every table
what am I missing?
private void SaveToLogTable(AuditScope auditScope)
{
foreach (var entry in ((AuditEventEntityFramework)auditScope.Event).EntityFrameworkEvent.Entries)
{
if(entry.Action is null) return;
if (TABLES.Any(x => x.T_TABLE_NAME.Equals(entry.Table)))
{
var newLog = new LOGS
{
LOG_ACTION = ACTIONS.FirstOrDefault(x => x.A_DESC == entry.Action)?.A_CODE,
LOG_DATE = DateTime.Now,
USERS = MyGlobalSettings.MyUser
};
if (entry.Changes != null)
{
foreach (var changes in entry.Changes)
{
var ch = new CHANGES
{
CH_COLUMN = changes.ColumnName,
CH_NEW_VALUE = changes.NewValue.ToString(),
CH_ORIGINAL_VALUE = changes.OriginalValue.ToString()
};
newLog.CHANGES.Add(ch);
}
}
if (entry.ColumnValues != null)
{
foreach (var kv in entry.ColumnValues)
{
var val = new VALUES
{
ColumnName = kv.Key,
ColumnValue = kv.Value.ToString()
};
newLog.VALUES.Add(val);
}
}
TABLES.First(x => x.T_TABLE_NAME.Equals(entry.Table)).LOGS.Add(newLog);
}
else
{
var table = new TABLES {T_TABLE_NAME = entry.Table};
var newLog = new LOGS
{
LOG_ACTION = ACTIONS.FirstOrDefault(x => x.A_DESC.Equals(entry.Action))?.A_CODE,
LOG_DATE = DateTime.Now,
LOG_USER_REFNO = MyGlobalSettings.MyUser.U_ROWID
//USERS = MyGlobalSettings.MyUser
};
if (entry.Changes != null)
{
foreach (var changes in entry.Changes)
{
var ch = new CHANGES
{
CH_COLUMN = changes.ColumnName,
CH_NEW_VALUE = changes.NewValue.ToString(),
CH_ORIGINAL_VALUE = changes.OriginalValue.ToString()
};
newLog.CHANGES.Add(ch);
}
}
if (entry.ColumnValues != null)
{
foreach (var kv in entry.ColumnValues)
{
var val = new VALUES
{
ColumnName = kv.Key,
ColumnValue = kv.Value is null? "": kv.Value.ToString()
};
newLog.VALUES.Add(val);
}
}
table.LOGS.Add(newLog);
//TABLES.Attach(table);
//TABLES.First(x => x.T_TABLE_NAME.Equals(entry.Table)).LOGS.Add(newLog);
TABLES.Add(table);
//TablesList.Add(table);
}
//entry.Entity
}
}
What is the best way to update multiple records in a list to speed up processing?
Currently, I'm updating about 15000 products, each with 3 different price sets and it takes the whole day to complete.
I need to update the prices all at once in code side, then commit those changes to the database in 1 go, instead of fetching each inventory item, updating its values, then attaching it to the context. Every single fetch is causing the delays.
Code
public void UpdatePricesFromInventoryList(IList<Domain.Tables.Inventory> invList)
{
var db = new UniStockContext();
foreach (var inventory in invList)
{
Domain.Tables.Inventory _inventory = db.Inventories
.Where(x => x.InventoryID == inventory.InventoryID)
.FirstOrDefault();
if (inventory.Cost.HasValue)
_inventory.Cost = inventory.Cost.Value;
else
_inventory.Cost = 0;
foreach (var inventoryPrices in inventory.AccInventoryPrices)
{
foreach (var _inventoryPrices in _inventory.AccInventoryPrices)
{
if (_inventoryPrices.AccInventoryPriceID == inventoryPrices.AccInventoryPriceID)
{
_inventoryPrices.ApplyDiscount = inventoryPrices.ApplyDiscount;
_inventoryPrices.ApplyMarkup = inventoryPrices.ApplyMarkup;
if (inventoryPrices.Price.HasValue)
_inventoryPrices.Price = inventoryPrices.Price.Value;
else
_inventoryPrices.Price = _inventory.Cost;
if (inventoryPrices.OldPrice.HasValue)
{
_inventoryPrices.OldPrice = inventoryPrices.OldPrice;
}
}
}
}
db.Inventories.Attach(_inventory);
db.Entry(_inventory).State = System.Data.Entity.EntityState.Modified;
}
db.SaveChanges();
db.Dispose();
}
I've also tried working my code according to this SOQ Entity Framework update/insert multiple entities
and it gave me and error. Here are the details:
Code:
public void UpdatePricesFromInventoryListBulk(IList<Domain.Tables.Inventory> invList)
{
var accounts = new List<Domain.Tables.Inventory>();
var db = new UniStockContext();
db.Configuration.AutoDetectChangesEnabled = false;
foreach (var inventory in invList)
{
accounts.Add(inventory);
if (accounts.Count % 1000 == 0)
{
db.Set<Domain.Tables.Inventory>().AddRange(accounts);
accounts = new List<Domain.Tables.Inventory>();
db.ChangeTracker.DetectChanges();
db.SaveChanges();
db.Dispose();
db = new UniStockContext();
}
}
db.Set<Domain.Tables.Inventory>().AddRange(accounts);
db.ChangeTracker.DetectChanges();
db.SaveChanges();
db.Dispose();
}
Error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I would suggest changing the following:
Domain.Tables.Inventory _inventory = db.Inventories
.Where(x => x.InventoryID == inventory.InventoryID)
.FirstOrDefault();
To
Domain.Tables.Inventory _inventory = db.Inventories
.Single(x => x.InventoryID == inventory.InventoryID);
I'd still add the db.Configuration.AutoDetectChangesEnabled = false; after getting the context, and also use AsNoTracking:
Turn off EF change tracking for any instance of the context
that is because you are hit the database context at every loop to increase the performance you should get all the Inventories by one hit ,this is your problem try the below code and you will notice the performance :
public void UpdatePricesFromInventoryList(IList<Domain.Tables.Inventory> invList)
{
var db = new UniStockContext();
invIdsArray = invList.select(x => x.InventoryID).ToArray();
IList<Domain.Tables.Inventory> invListFromDbByOneHit = db.Inventories.Where(x => invIdsArray.Contains(x.InventoryID)).Tolist();
foreach (var inventory in invListFromDbByOneHit)
{
//Domain.Tables.Inventory _inventory = db.Inventories
//.Where(x => x.InventoryID == inventory.InventoryID)
//.FirstOrDefault();
if (inventory.Cost.HasValue)
_inventory.Cost = inventory.Cost.Value;
else
_inventory.Cost = 0;
foreach (var inventoryPrices in inventory.AccInventoryPrices)
{
foreach (var _inventoryPrices in _inventory.AccInventoryPrices)
{
if (_inventoryPrices.AccInventoryPriceID == inventoryPrices.AccInventoryPriceID)
{
_inventoryPrices.ApplyDiscount = inventoryPrices.ApplyDiscount;
_inventoryPrices.ApplyMarkup = inventoryPrices.ApplyMarkup;
if (inventoryPrices.Price.HasValue)
_inventoryPrices.Price = inventoryPrices.Price.Value;
else
_inventoryPrices.Price = _inventory.Cost;
if (inventoryPrices.OldPrice.HasValue)
{
_inventoryPrices.OldPrice = inventoryPrices.OldPrice;
}
}
}
}
db.Inventories.Attach(_inventory);
db.Entry(_inventory).State = System.Data.Entity.EntityState.Modified;
}
db.SaveChanges();
db.Dispose();
}
I am pretty new to MOQ and I am in learning right now. I got task that I need to write unit test But I am getting the below error which I couldn't able to find. Please anyone help me with this. Also please review the code and give me some advises if my testcase needs changes.
Expection: IAcronisService.GetActivitiesFromDate("mygroup", 5/24/2016
8:33:34 PM) invocation failed with mock behavior Strict.....
for Save method(I have commented at save method where the exception has been thrown)
Process method calls save method
public int Process()
{
AcronisService = AcronisSvcManager.Get(ClientFactory, DataProviderFactory, LogAdapter);
DataObject backupGroupsDO = GetListOfAllCurrentGroups();
int activitiesSavedCount = Save(backupGroupsDO);
return activitiesSavedCount;
}
When I debug I also have seen the below line when I mouse over at first line on above process method. I thought service object is not calling/mocking. Is this anything to do with above exception? Please suggest some changes.
(IAcronisServiceProxy)AcronisService).AcronisURL threw a exception of type MOQ.MockException.
Save Method
private int Save(DataObject backupGroupsDO)
{
int count = 0;
foreach (DataRecord dr in backupGroupsDO.DataRecord)
{
BackupGroup backupGroup = new BackupGroup(dr);
// Get all activities for each group
AcronisClient.DataModel.Activity.ActivitiesResponse acronisActivities;
if (backupGroup.LastActivityDate == null)
{
// Get all activities for each group
***//Got Exception at this line***
acronisActivities = AcronisService.GetActivitiesFromDate(backupGroup.GroupName, DateTime.Now.AddDays(-90));
}
else
{
acronisActivities = AcronisService.GetActivitiesFromDate(backupGroup.GroupName, backupGroup.LastActivityDate);
}
if (acronisActivities == null || acronisActivities.Activities == null)
{
// Stop processing b/c might be an issue with the connection to Acronis
LogAdapter.LogError(KCBLog.Main, "Stopped processing activities, possible Acronis connection issue with getting Activities");
return -1;
}
var lastBackUpActivity = acronisActivities.Activities.OrderByDescending(z => z.StartTime).FirstOrDefault();
List<string> lastSuccessfulActivities = new List<string>();
List<string> lastActivities = new List<string>();
foreach (var acronisActivity in acronisActivities.Activities)
{
Kaseya.KCB.Common.DataModels.AcronisActivity activity = new AcronisActivity();
activity.BackupPlanId = acronisActivity.BackupPlanId;
activity.BytesProcessed = acronisActivity.BytesProcessed;
activity.BytesSaved = acronisActivity.BytesSaved;
activity.Cause = acronisActivity.CompletionResult == null ? null : acronisActivity.CompletionResult.Cause;
activity.Reason = acronisActivity.CompletionResult == null ? null : acronisActivity.CompletionResult.Reason;
activity.Effect = acronisActivity.CompletionResult == null ? null : acronisActivity.CompletionResult.Effect;
activity.DateCreated = DateTime.Now;
activity.FinishTime = acronisActivity.FinishTime;
activity.GroupId = backupGroup.Id;
activity.Id = acronisActivity.Id;
activity.InitiatedBy = acronisActivity.InitiatedBy;
activity.InstanceId = acronisActivity.InstanceId;
activity.IsRootActivity = (bool)acronisActivity.IsRootActivity;
activity.ParentActivityId = acronisActivity.ParentActivityId;
activity.PartitionId = PartitionId;
activity.StartTime = acronisActivity.StartTime;
activity.State = acronisActivity.State;
activity.Status = acronisActivity.Status;
activity.Title = acronisActivity.Title;
activity.UpdateTime = acronisActivity.UpdateTime;
AcronisActivityDataProvider.AddUpdateAcronisActivity(activity);
AcronisClient.DataModel.Activity.Activity lastSuccessfulActivity = acronisActivities.Activities.Where(z => z.Status == "ok" && z.Title.Contains("Running backup plan") && z.InstanceId==acronisActivity.InstanceId).OrderByDescending(z => z.FinishTime).FirstOrDefault();
var lastActivity = acronisActivities.Activities.Where(z => z.Title.Contains("Running backup plan") && z.InstanceId == acronisActivity.InstanceId).OrderByDescending(z => z.FinishTime).FirstOrDefault();
if (!string.IsNullOrEmpty(acronisActivity.InstanceId))
{
DataRecord assetDR = AssetDataProvider.GetByInstanceId(acronisActivity.InstanceId, PartitionId);
if (assetDR != null)
{
var assetId = assetDR.FindValue<string>("id", "");
if (lastSuccessfulActivity != null && !lastSuccessfulActivities.Contains(acronisActivity.InstanceId))
{
AssetDataProvider.UpdateLastSuccessfulActivityId(assetId, lastSuccessfulActivity.ParentActivityId);
lastSuccessfulActivities.Add(acronisActivity.InstanceId);
}
if (lastActivity != null && !lastActivities.Contains(acronisActivity.InstanceId))
{
AssetDataProvider.UpdateLastActivityId(assetId, lastActivity.ParentActivityId);
lastActivities.Add(acronisActivity.InstanceId);
}
}
}
count++;
}
if (acronisActivities.Activities != null && acronisActivities.Activities.Count>0)
{
//backupGroup.LastActivityDate = lastBackUpActivity.StartTime;
BackupGroupDataProvider.UpdateLastBackupGroupActivityDate(backupGroup.Id, lastBackUpActivity.StartTime);
}
}
return count;
}
Test Method I have writtern,
public void Test()
{
string groupName = "mygroup";
string mybackupAccountName = "mybackupaccount";
decimal PartitionId = 9m;
DateTime lastActivityDate = DateTime.Parse("2016-08-14T20:47:05");
string instanceId = "utinstanceId";
string assetId = "123";
DataRecord asset = new DataRecord();
asset.AddField("id", 123);
DataObject backupGroupsDO = new DataObject();
DataRecord groupDataRecord = new DataRecord();
groupDataRecord.AddField("id", 123);
groupDataRecord.AddField("partitionId", PartitionId);
groupDataRecord.AddField("groupName", groupName);
//groupDataRecord.AddField("lastActivityDate", lastActivityDate);
groupDataRecord.AddField("backupAccountName", mybackupAccountName);
backupGroupsDO.DataRecord.Add(groupDataRecord);
AcronisActivity acronisActivity = new AcronisActivity();
acronisActivity.BackupPlanId = "utBackupPlanId";
ActivitiesResponse activitiesResponse = new ActivitiesResponse();
AcronisClient.DataModel.Activity.Activity activity = new AcronisClient.DataModel.Activity.Activity();
activity.BackupPlanId = "utackupPlanId";
activity.BytesProcessed = 124674;
activity.BytesSaved = 06446;
activity.CompletionResult = new CompletionResult()
{
Cause = "utCause",
Reason = "utReason",
Effect = "utEffect"
};
activity.FinishTime = DateTime.Parse("2016-08-14T20:47:04");
activity.Id = "utId";
activity.InitiatedBy = "utInitiatedBy";
activity.InstanceId = "utInstanceId";
activity.IsRootActivity = true;
activity.ParentActivityId = "utParentActivityId";
activity.StartTime = DateTime.Parse("2016-08-14T20:47:02");
activity.State = "utState";
activity.Status = "utStatus";
activity.Title = "utTitle";
activity.UpdateTime = DateTime.Parse("2016-08-14T20:47:03");
activitiesResponse.Activities = new List<AcronisClient.DataModel.Activity.Activity>();
activitiesResponse.Activities.Add(activity);
var moqFactory = new MockRepository(MockBehavior.Strict);
var moqDataProviderFactory = moqFactory.Create<IDataProviderFactory>();
var moqDataProvider = moqFactory.Create<IDataProvider>();
var moqLogAdapter = moqFactory.Create<ILogAdapter>();
var moqAcronisServiceManager = moqFactory.Create<IAcronisServiceManager>();
var moqAcronisService = moqFactory.Create<IAcronisService>();
var moqAssetDataProvider = moqFactory.Create<IAssetDataProvider>();
var moqAcronisActivityDataProvider = moqFactory.Create<IAcronisActivityDataProvider>();
var moqBackupGroupDataProvider = moqFactory.Create<IBackupGroupDataProvider>();
Credential MSPCredential = new Credential();
moqDataProviderFactory.Setup(m => m.BackupGroupDataProvider.GetBackupGroups()).Returns(backupGroupsDO);
moqAcronisServiceManager.Setup(m => m.Get(It.IsAny<IRestClientFactory>(), It.IsAny<IDataProviderFactory>(), It.IsAny<ILogAdapter>(), "")).Returns(moqAcronisService.Object);
moqDataProvider.Setup(m => m.VerifyPartitionId(ref PartitionId));
moqDataProvider.Setup(m => m.ExecuteNonQuery(It.IsAny<AddUpdateAcronisActivity>())).Returns(1);
moqAcronisService.Setup(m => m.GetActivitiesFromDate(groupName, lastActivityDate)).Returns(activitiesResponse);
moqAcronisActivityDataProvider.Setup(m => m.AddUpdateAcronisActivity(acronisActivity));
moqAssetDataProvider.Setup(m => m.GetByInstanceId(instanceId, PartitionId,1)).Returns(asset);
moqAssetDataProvider.Setup(m => m.UpdateLastActivityId(assetId, activity.ParentActivityId));
moqAssetDataProvider.Setup(m => m.UpdateLastSuccessfulActivityId(assetId, activity.ParentActivityId));
moqBackupGroupDataProvider.Setup(m => m.UpdateLastBackupGroupActivityDate("1234", lastActivityDate));
// moqAcronisService.Setup(m => m.GetActivitiesFromDate(groupName, Convert.ToDateTime("2016-08-18T13:18:40.000Z"))).Returns(activitiesResponse);
ActivityHarvester activityHarvester = new ActivityHarvester();
activityHarvester.PartitionId = PartitionId;
activityHarvester.DataProvider = moqDataProvider.Object;
activityHarvester.LogAdapter = moqLogAdapter.Object;
activityHarvester.AcronisSvcManager = moqAcronisServiceManager.Object;
activityHarvester.DataProviderFactory = moqDataProviderFactory.Object;
activityHarvester.AcronisService = moqAcronisService.Object;
activityHarvester.AssetDataProvider = moqAssetDataProvider.Object;
activityHarvester.BackupGroupDataProvider = moqBackupGroupDataProvider.Object;
activityHarvester.AcronisActivityDataProvider = moqAcronisActivityDataProvider.Object;
activityHarvester.process();//*process method calls above save method method*
moqFactory.VerifyAll();
}
From your example, your setup for IAcronisService.GetActivitiesFromDate shows that it is expecting lastActivityDate of 2016-08-14T20:47:05 based on the code but the error shows that you used a different date 5/24/2016 8:33:34 PM than expected. As the moq behavior is Strict, this
Causes the mock to always throw an exception for invocations that don't have a corresponding setup.
You can make the setup a little more flexible by using It.IsAny<DateTime>()
moqAcronisService
.Setup(m => m.GetActivitiesFromDate(groupName, It.IsAny<DateTime>()))
.Returns(activitiesResponse);
or changing the behavior in your moq factory to use Default or Loose MockBehavior.
My scenario is to send invoice details (in PDF format) to customer's emailId on paynow button click event.
I have tried the following but getting exception after calling
actionPDF.BuildPdf(ControllerContext)
Exception is
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding
Code:
dbDetails _db = new dbDetails();
[HttpPost]
public JsonResult Add(Model mdl)
{
using (TransactionScope _ts = new TransactionScope())
{
//Insertion logic of invoice goes here
...
...
int i = _db.SaveChanges();
// if successfull insertion
if(i > 0)
{
var actionPDF = new Rotativa.ActionAsPdf("GetPdfReceipt", new { RegId = _receiptDetails.StudentRegistrationID.Value })
{
FileName = "Receipt.pdf"
};
// Dynamic student receipt pdf
***Getting exception here****
var byteArrayDynamic = actionPDF.BuildPdf(ControllerContext);
// Mail sending logic
......
......
_ts.Complete();
}
}
}
public ActionResult GetPdfReceipt(int RegId)
{
Common _cmn = new Common();
var _studentRegistration = _db.StudentRegistrations
.AsEnumerable()
.Where(r => r.Id == RegId)
.FirstOrDefault();
var _mdlReceiptPdf = new ReceiptPdfVM
{
CentreCode = _studentRegistration.StudentWalkInn.CenterCode.CentreCode,
CompanyAddress = _studentRegistration.StudentWalkInn.CenterCode.Address,
CompanyPhoneNo = _studentRegistration.StudentWalkInn.CenterCode.PhoneNo,
CourseFee = _studentRegistration.TotalCourseFee.Value,
CourseTitle = string.Join(",", _studentRegistration.StudentRegistrationCourses
.Select(rc => rc.MultiCourse.CourseSubTitle.Name)),
CROName = _studentRegistration.StudentWalkInn.CROCount == (int)EnumClass.CROCount.ONE ? _studentRegistration.StudentWalkInn.Employee1.Name :
_studentRegistration.StudentWalkInn.Employee1.Name + ',' + _studentRegistration.StudentWalkInn.Employee2.Name,
Duration = _studentRegistration.TotalDuration.Value,
ReceiptDate = _studentRegistration.StudentReceipts.Last(sr => sr.Status == true).DueDate.Value.ToString("dd/MM/yyyy"),
ReceiptNo = _studentRegistration.StudentReceipts.Last(sr => sr.Status == true).ReceiptNo,
RegistrationNumber = _studentRegistration.RegistrationNumber,
ServiceTax = _studentRegistration.TotalSTAmount.Value,
StudentMaskedEmailId = _cmn.MaskString(_studentRegistration.StudentWalkInn.EmailId, "email"),
StudentMaskedMobileNo = _cmn.MaskString(_studentRegistration.StudentWalkInn.MobileNo, "mobile"),
StudentName = _studentRegistration.StudentWalkInn.CandidateName,
ServiceTaxRegistrationNo = _studentRegistration.StudentWalkInn.CenterCode.STRegNo,
TotalAmount = _studentRegistration.TotalAmount.Value,
TotalAmountInWords = _cmn.NumbersToWords(_studentRegistration.TotalAmount.Value).ToUpper(),
TotalCourseFeePaid = _studentRegistration.StudentReceipts
.Where(r => r.Status == true)
.Sum(r => r.Fee.Value),
ManagerName = _cmn.GetManager(_studentRegistration.StudentWalkInn.CenterCodeId.Value)
.Name,
ReceiptDetailsList = _db.StudentReceipts
.AsEnumerable()
.Where(rc => rc.StudentRegistrationID == RegId)
.Select(rc => new ReceiptPdfVM.ReceiptDetails
{
CourseFee = rc.Fee.Value,
DatePaid = rc.DueDate.Value.ToString("dd/MM/yyyy"),
ReceiptNo = rc.ReceiptNo
}).ToList()
}
return View("Receipts", _mdlReceiptPdf);
}
protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
How to solve this issue? Any help will be highly appreciated.
I think the problem is that while generating the PDF document your pending database transaction times out. Move the _ts.Complete to before you generate the PDF.
dbDetails _db = new dbDetails();
[HttpPost]
public JsonResult Add(Model mdl)
{
using (TransactionScope _ts = new TransactionScope())
{
//Insertion logic of invoice goes here
...
...
int i= _db.SaveChanges();
//if successfull insertion
if(i>0)
{
_ts.Complete();
var actionPDF = new Rotativa.ActionAsPdf("GetPdfReceipt", new { RegId = _receiptDetails.StudentRegistrationID.Value })
{
FileName = "Receipt.pdf"
};
//Dynamic student receipt pdf
***Getting exception here****
var byteArrayDynamic = actionPDF.BuildPdf(ControllerContext);
//Mail sending logic
......
......
}
}
}