EF Core "добавить, если он не существует", запрашивая вложенные (включенные) свойства? - PullRequest
0 голосов
/ 14 октября 2019

Я довольно новичок в этом динамическом создании лямбды. Это было бы довольно легко сделать, если бы C # работал как JS / TS, но, к сожалению, это не так. Теперь моя идея состоит в том, чтобы сделать что-то вроде этого:

User u = new User() { Email = "user@app.com", Password = "aaaaaa" };
UserMetadata m = new UserMetadata() { IdUser = u.Id, User = u, FirstName = "User" };

db.Users.AddIfNotExists(x => x.Email, u);
db.UserMetadatas.AddIfNotExists(x => x.User.Email, m);
db.SaveChanges();

Обратите внимание, что в строке db.UserMetadatas.AddIfNotExists я хочу добавить UserMetadata class , только если его вложенное свойствоUser.Email не совпадает.

У меня уже есть одно свойство (оно работает с User), но когда я пытаюсь сделать это с UserMetadata, оно говорит мне, что Email не является частью UserMetadata (чтоимеет смысл). Кажется, код пропускает (или не создает) поиск во вложенном свойстве.

Моя идея состоит в том, чтобы иметь общий метод для использования с любым объектом, мне достаточно двух уровней.

Мой текущий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using App_Entities.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.DependencyInjection;

namespace App_Entities
{
    public static class DbContextExtensions
    {
        private static Expression ReplaceParameter(Type t, Expression oldExpression, ParameterExpression newParameter)
        {
            switch (oldExpression.NodeType)
            {
                case ExpressionType.MemberAccess:
                    var m = (MemberExpression)oldExpression;
                    return Expression.MakeMemberAccess(newParameter, m.Member); // ERROR IS HERE
                case ExpressionType.New:
                    var newExpression = (NewExpression)oldExpression;
                    var arguments = new List<Expression>();
                    foreach (var a in newExpression.Arguments)
                        arguments.Add(ReplaceParameter(t, a, newParameter));
                    var returnValue = Expression.New(newExpression.Constructor, arguments.ToArray());
                    return returnValue;
                default:
                    throw new NotSupportedException("Unknown expression type for AddOrUpdate: " + oldExpression.NodeType);
            }
        }

        public static LambdaExpression CreateExpression(Type type, string propertyName)
        {
            var param = Expression.Parameter(type, "p");
            Expression body = param;
            foreach (var member in propertyName.Split('.'))
                body = Expression.PropertyOrField(body, member);
            return Expression.Lambda(body, param);
        }

        public static void AddIfNotExists<T>(this DbSet<T> dbSet, Expression<Func<T, object>> identifierExpression, T data) where T : class
        {
            var t = typeof(T);
            var keyObject = identifierExpression.Compile()(data);
            var parameter = Expression.Parameter(typeof(T), "p");
            var lambda = Expression.Lambda<Func<T, bool>>(Expression.Equal(ReplaceParameter(typeof(T), identifierExpression.Body, parameter), Expression.Constant(keyObject)), parameter);
            var dbVal = dbSet.FirstOrDefault(lambda);
            if (dbVal == null)
                dbSet.Add(data);
        }

        public static void EnsureSeeded(this AppDbContext db, bool isDevelopment)
        {
            User u = new User() { Email = "user@app.com", Password = "aaaaaa" };
            UserMetadata m = new UserMetadata() { IdUser = u.Id, User = u, FirstName = "User" };

            db.Users.AddIfNotExists(x => x.Email, u); // This works
            db.UserMetadatas.AddIfNotExists(x => x.User.Email, m); // This doesn't :(
            db.SaveChanges();
        }
    }
}

Заранее спасибо! :)

...