csharp 实现.AddOrUpdate也支持nullables

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp 实现.AddOrUpdate也支持nullables相关的知识,希望对你有一定的参考价值。

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace System.Data.Entity
{
    internal static class DbSeeder
    {
        public static TEntity[] AddOrUpdate<TEntity>(this DbContext context, Expression<Func<TEntity, object>> identifiers, params TEntity[] entities)
            where TEntity : class
        {
            // EF .AddOrUpdate is a bit buggy...
            var primaryKeys = PrimaryKeys<TEntity>();
            var properties = Properties(identifiers);

            for (var i = 0; i < entities.Length; i++)
            {
                // build where condition for "identifiers"
                var parameter = Expression.Parameter(typeof(TEntity));
                var matches = properties.Select(p => Expression.Equal(
                    Expression.Property(parameter, p),
                    Expression.Constant(p.GetValue(entities[i]), p.PropertyType)));
                var match = Expression.Lambda<Func<TEntity, bool>>(
                    matches.Aggregate((p, q) => Expression.AndAlso(p, q)),
                    parameter);

                // match "identifiers" for current item
                var current = context.Set<TEntity>().SingleOrDefault(match);
                if (current != null)
                {
                    // update primary keys
                    foreach (var k in primaryKeys)
                        k.SetValue(entities[i], k.GetValue(current));

                    // update all the values
                    context.Entry(current).CurrentValues.SetValues(entities[i]);

                    // replace updated item
                    entities[i] = current;
                }
                else
                {
                    // add new item
                    entities[i] = context.Set<TEntity>().Add(entities[i]);
                }
            }

            return entities;
        }

        private static PropertyInfo[] Properties<TEntity>(Expression<Func<TEntity, object>> identifiers)
            where TEntity : class
        {
            // e => e.SomeValue
            var direct = identifiers.Body as MemberExpression;
            if (direct != null)
            {
                return new[] { (PropertyInfo)direct.Member };
            }

            // e => (object)e.SomeValue
            var convert = identifiers.Body as UnaryExpression;
            if (convert != null)
            {
                return new[] { (PropertyInfo)((MemberExpression)convert.Operand).Member };
            }

            // e => new { e.SomeValue, e.OtherValue }
            var multiple = identifiers.Body as NewExpression;
            if (multiple != null)
            {
                return multiple.Arguments
                               .Cast<MemberExpression>()
                               .Select(a => (PropertyInfo)a.Member)
                               .ToArray();
            }

            throw new NotSupportedException();
        }

        private static PropertyInfo[] PrimaryKeys<TEntity>()
            where TEntity : class
        {
            return typeof(TEntity).GetProperties()
                                  .Where(p => Attribute.IsDefined(p, typeof(KeyAttribute))
                                           || "Id".Equals(p.Name, StringComparison.Ordinal))
                                  .ToArray();
        }
    }
}

以上是关于csharp 实现.AddOrUpdate也支持nullables的主要内容,如果未能解决你的问题,请参考以下文章

csharp [AddOrUpdate]あれば更新,なければ添加#ExtensionMethod

AddOrUpdate 违反唯一索引

如何在 EF 4.3 中使用带有复杂键的 AddOrUpdate 播种数据

将 AddOrUpdate 与 Entity Framework 6 Repository 一起使用的单元测试方法

如何在 Entity Framework 4.4 中实现 DBSet.AddOrUpdate?

有没有办法让 DbSet.AddOrUpdate 区分大小写?