Entity Framework 4 Custom Logic Saving Changes
I am trying to add some custom logic to my entities. Each entity has a CreatedBy & LastUpdatedBy property.
I have added the code below which works fine if I am adding e.g. A Person and their Address in on go.
However if I add the Person and call context.SaveChanges() then add their Address and call context.SaveChanges(). The code executes but the value for "entry" is null and therefore CreatedBy & LastUpdatedBy are not populated.
CustomRepository.CurrentUser
just gets the user name.
ObjectSet = context.CreateObjectSet<TEntity>();
BusinessEntities.Person person = new BusinessEntities.Person()
{
TitleRef = 123,
FirstName = "FirstName",
Surname = "Surname",
PhoneNumber = "PhoneNumber",
MobileNumber = "MobileNumber",
EmailAddress = "EmailAddress",
};
ObjectSet.AddObject(entity);
Context.SaveChanges();
PersonAddress personAddress = new BusinessEntities.PersonAddress
{
StartDate = DateTime.Now,
EndDate = DateTime.Now,
OtherResidents = "OtherResidents",
CurrentAddress = true,
Address = new Address
{
Address1 = "Address1",
Address2 = "Address2",
Address3 = "Address3"
}
};
Context.SaveChanges();
public override int SaveChanges(SaveOptions options)
{
foreach (ObjectStateEntry entry in
ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified))
{
System.Collections.ObjectModel.ReadOnlyCollection<FieldMetadata> fieldsMetaData = entry.CurrentValues
.DataRecordInfo.FieldMetadata;
FieldMetadata createdField = fieldsMetaData
.Where(f => f.FieldType.Name == "CreatedBy").FirstOrDefault();
FieldMetadata modifiedField = fieldsMetaData
.Where(f => f.FieldType.Name == "LastUpdatedBy").FirstOrDefault();
if (modifiedField.FieldType != null)
{
string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
if (fieldTypeName == PrimitiveTypeKind.String.ToString())
{
if (entry.CurrentValues[createdField.Ordinal].ToString() == null ||
entry.CurrentValues[createdField.Ordinal].ToString() == String.Empty)
{
entry.CurrentValues.SetString(createdField.Ordinal, CustomRepository.CurrentUser);
}
entry.CurrentValues.SetString(modifiedField.Ordinal, CustomRepository.CurrentUser);
}
}
}
return base.SaveChanges(options);
}
------------------------Original Method-----------------------------
private void Initialize()
{
// Creating proxies requires the use of the ProxyDataContractResolver and
// may allow lazy loading which can expand the loaded graph during serialization.
ContextOptions.ProxyCreationEnabled = false;
ObjectMaterialized += new ObjectMaterializedEventHandler(HandleObjectMaterialized);
OnContextCreated();
}
private void OnContextCreated()
{
this.SavingChanges += Context_SavingChanges;
}
private void Context_SavingChanges(object sender, EventArgs e)
{
try
{
IEnumerable<ObjectStateEntry> objectStateEntries =
from ose
in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added
| EntityState.Modified)
where ose.Entity != null
select ose;
foreach (ObjectStateEntry entry in objectStateEntries)
{
System.Collections.ObjectModel.ReadOnlyCollection<FieldMetadata> fieldsMetaData = entry.CurrentValues
.DataRecordInfo.FieldMetadata;
FieldMetadata createdField = fieldsMetaData
.Where(f => f.FieldType.Name == "CreatedBy").FirstOrDefault();
FieldMetadata modifiedField = fieldsMetaData
.Where(f => f.FieldType.Name == "LastUpdatedB开发者_开发技巧y").FirstOrDefault();
if (modifiedField.FieldType != null)
{
string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
if (fieldTypeName == PrimitiveTypeKind.String.ToString())
{
if (entry.CurrentValues[createdField.Ordinal].ToString() == null ||
entry.CurrentValues[createdField.Ordinal].ToString() == String.Empty)
{
entry.CurrentValues.SetString(createdField.Ordinal, CustomRepository.CurrentUser);
}
entry.CurrentValues.SetString(modifiedField.Ordinal, CustomRepository.CurrentUser);
}
}
}
}
}
I eventually got the answer. I needed to call Context.DetectChanges() before I Save() otherwise the changes were not detected.
You should probably handle the SavingChanges
event instead of over-riding the method.
Also, why not make your entities inherit from a base class or implement an interface rather than using reflection? You can do this in the T4 template if you're using model/database first, or directly if you're using code first, and it will give you a better result in the long term than reflection would. You can also then write generic filters to find entities modified in a date range, because you can work against your interface.
I use ObjectStateManager.GetObjectStateEntries(EntityState.Modified).OfType(Of T)
(or whichever state I want, for whichever entity type I want) - it lets me work against the actual entity rather than the ObjectStateEntry.
精彩评论