Я довольно новичок в этом динамическом создании лямбды. Это было бы довольно легко сделать, если бы 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();
}
}
}
Заранее спасибо! :)