4

私は EF 5 Code-First ソリューションに取り組んでおり、リポジトリ パターンを使用して変更されたエンティティで既存のエンティティを更新しようとしています。

    public void UpdateValues(T originalEntity, T modifiedEntity)
    {
        _uow.Context.Entry(originalEntity).CurrentValues.SetValues(modifiedEntity);

私の簡略化されたドメイン オブジェクトは次のようになります。

public class PolicyInformation : DomainObject
{
     //Non-navigation properties
     public string Description {get;set;}
     public bool Reinsurance {get;set;}
     ...
     //Navigation properties
     LookupListItemFormType FormType {get;set;}
     ...
}

私が抱えている問題は、CurrentValues.SetValues(modifiedEntity);メソッドがスカラーおよび複合型のプロパティのみを更新しているように見え、Navigation プロパティは更新していないように見えることです。私はこれが多くの人に起こっているのを見てきましたが、それがなぜなのかはまだわかりません. ただし、すべてを実行した後にこれらのナビゲーション プロパティを手動で設定すると、UpdateValuesすべて正常に動作することがわかりました。

            _policyInfoRepo.UpdateValues(existingPolicyInfo, info);
            existingPolicyInfo.FormType = info.FormType;

問題は、汎用リポジトリを使用しているためです。ドメイン オブジェクトのナビゲーション プロパティのリストを取得するにはどうすればよいですか? おそらくlinq、リフレクション、またはその他の方法を使用して、リポジトリの更新メソッドがそれらをループして自動的に設定できるようにしますか?

このようなもの:

    public void UpdateValues(T originalEntity, T modifiedEntity)
    {
        //Set non-nav props
        _uow.Context.Entry(originalEntity).CurrentValues.SetValues(modifiedEntity);
        //Set nav props
        var navProps = GetNavigationProperties(originalEntity);
        foreach(var navProp in navProps)
        {
           //Set originalEntity prop value to modifiedEntity value
        }

ありがとう!

4

4 に答える 4

6

以下はEF6で書きましたが、全てEF5と互換性があると思います。コードの背後にある一般的な考え方は、System.Data.Metadata.Edmの優れたクラスを使用してナビゲーション プロパティを取得し、それらのプロパティ名のリフレクションを使用して、更新するオブジェクトの実際のプロパティを取得することです。

私の例は、できるだけ一般的でありながら完全なものにしたかったのです。質問者の場合、明らかに「context」を「_uow.Context」に置き換えます。

public class MyClass<T> where T : class //T really needs to always be an entity, 
                                        //but I don't know a general parent type
                                        //for that. You could leverage partial classes
                                        //to define your own type.
{
    public MyEntities context { get; set; }

    public void UpdateValues(T originalEntity, T modifiedEntity)
    {
        //Set non-nav props
        context.Entry(originalEntity).CurrentValues.SetValues(modifiedEntity);
        //Set nav props
        var navProps = GetNavigationProperties(originalEntity);
        foreach (var navProp in navProps)
        {
            //Set originalEntity prop value to modifiedEntity value
            navProp.SetValue(originalEntity, navProp.GetValue(modifiedEntity));                
        }
    }

    public List<System.Reflection.PropertyInfo> GetNavigationProperties(T entity)
    {
        List<System.Reflection.PropertyInfo> properties = new List<System.Reflection.PropertyInfo>();
        //Get the entity type
        Type entityType = entity.GetType();
        //Get the System.Data.Entity.Core.Metadata.Edm.EntityType
        //associated with the entity.
        var entitySetElementType = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext.CreateObjectSet<T>().EntitySet.ElementType;
        //Iterate each 
        //System.Data.Entity.Core.Metadata.Edm.NavigationProperty
        //in EntityType.NavigationProperties, get the actual property 
        //using the entityType name, and add it to the return set.
        foreach (var navigationProperty in entitySetElementType.NavigationProperties)
        {
            properties.Add(entityType.GetProperty(navigationProperty.Name));
        }
        return properties;
    }
}
于 2014-01-07T19:44:37.300 に答える
5

ああ、LINQ (およびusing) の栄光:

public List<PropertyInfo> GetNavigationProperties(T entity)
{
    var t = entity.GetType();
    var elementType = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<T>().EntitySet.ElementType;
    return elementType.NavigationProperties.Select(np => entityType.GetProperty(np.Name)).ToList();
}

staticこれは、次のシグネチャを使用してメソッドを介して実装することもできます。

public static List<PropertyInfo> GetNavigationProperties<T>(DbContext context)
{
    var t = typeof(T);
    ...
于 2014-04-10T10:26:55.627 に答える
4

Zevの答えに基づく:

public List<PropertyInfo> GetNavigationProperties<T>(DbContext context) where T : class
{
    var entityType = typeof(T);
    var elementType = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<T>().EntitySet.ElementType;
    return elementType.NavigationProperties.Select(property => entityType.GetProperty(property.Name)).ToList();
}
于 2014-11-25T10:30:29.713 に答える
2
    public static T Clone<T>(this T entity) where T : class
    {
        var type = entity.GetType();
        var clone = Activator.CreateInstance(type);

        var navigationProperties = type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.DeclaredOnly);

        foreach (var property in type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty))
        {
            //if (property.Module.ScopeName == "EntityProxyModule") continue;
            if (navigationProperties.Contains(property)) continue;

            if (property.CanWrite)
            {
                property.SetValue(clone, property.GetValue(entity, null), null);
            }
        }

        return (T)clone;
    }

ナビゲーション プロパティのみが動的プロキシで直接定義されるため、BindingFlags.DeclaredOnly を使用するとそれらが除外されます。

別の (コメントアウトされた) メソッドは、property.Module.ScopeName を使用してナビゲーション プロパティを区別します。ナビゲーション プロパティの場合、この値は "EntityProxyModule" になりますが、他のプロパティの場合、この値は最初に EF コードを定義したプロジェクトの dll 名になります。のドメインクラス。

この Clone メソッドを使用して、Json シリアル化 (循環参照を回避) の準備が整った EF コードの最初のドメイン オブジェクトを複製しますが、ナビゲーション プロパティのリストを取得する方法に関する作成者のクエリは含まれています。

于 2015-12-25T13:04:44.417 に答える