开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜