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();