0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

EntityFramework エンティティのナビゲーションプロパティをすべてnull にするような拡張メソッド

Last updated at Posted at 2021-05-27

エンティティのナビゲーションプロパティが何か設定されていると都合が悪い場面があるとか何とかで、いっそすべて null クリアしてしまえ、って感じの拡張。
ようこそExpression 沼へ。

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;

    class Program
    {

        static void Main(string[] args)
        {
            var buzz = new Buzz();
            buzz.ClearReference();

            Console.WriteLine("process end.");
            Console.ReadLine();
        }
    }

    static class ClearReferencesExtension
    {
        static Dictionary<Type, ClearReferenceActions> ClearEntityReferences = new Dictionary<Type, ClearReferenceActions>();

        public static void ClearReference<TEntity>(this TEntity entity)
        {
            if (!ClearEntityReferences.ContainsKey(typeof(TEntity)))
            {
                CreateClearReference<TEntity>();
            }
            var clearActions = ClearEntityReferences[typeof(TEntity)];
            foreach(var action in clearActions.Actions)
            {
                action.Invoke(entity);
            }
        }
        static void CreateClearReference<TEntity>()
        {
            var clear = new ClearReferenceActions();
            var entityType = typeof(TEntity);
            var parameter = Expression.Parameter(typeof(object), "$entity");

            var properties = typeof(Buzz).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
            foreach (var property in properties)
            {
                if (property.PropertyType.IsValueType)
                {
                    continue;
                }
                if (property.PropertyType == typeof(string))
                {
                    continue;
                }
                var nullable = property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>);
                if (nullable)
                {
                    var baseType = Nullable.GetUnderlyingType(property.PropertyType);
                    if (baseType.IsValueType)
                    {
                        continue;
                    }
                    if (baseType == typeof(string))
                    {
                        continue;
                    }
                }
                var propertyAccess = Expression.Property(Expression.Convert(parameter, entityType), property);
                var assign = Expression.Assign(propertyAccess, Expression.Constant(null, property.PropertyType));
                Expression<Action<object>> lambda = Expression.Lambda<Action<object>>(assign, parameter);
                var action = lambda.Compile();
                clear.Actions.Add(action);
            }

            ClearEntityReferences.Add(entityType, clear);
        }
        class ClearReferenceActions
        {
            public List<Action<object>> Actions = new List<Action<object>>();

        }
    }

注意

EF がマッピングしそうなプロパティを除外しようとしているけど、 DateTimeOffset とかHieralkeyId とかその他ValueObject的なものは一切考慮してないのでそういうプロパティを使っている場合はクリア対象にするしないを注意深く設定する必要がある。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?