如何以通用方式排除具有 EF4/CTP5 流畅映射的枚举属性?

发布于 2024-10-21 19:44:47 字数 1135 浏览 2 评论 0原文

我只是深入研究代码优先与实体框架 CTP5 的使用。为了减轻配置数据库映射的痛苦,我为自己创建了一个小帮助器类,作为任何自定义映射的基类,但我无法弄清楚如何使该方法中的最后一条语句起作用。

我正在查找 Enum 类型的所有公共属性,然后为给定类型上找到的每个属性调用 .Ignore 方法。该代码使用 Fasterflect 进行反射,并使用一些 ForEach 帮助程序,但代码的作用应该相当明显。

internal abstract class AbstractMappingProvider<T> : IMappingProvider where T : class
{
    public EntityTypeConfiguration<T> Map { get; private set; }

    public virtual void DefineModel( ModelBuilder modelBuilder )
    {
        Map = modelBuilder.Entity<T>();

        Map.ToTable( typeof(T).Name );

        typeof(T).Properties( Flags.Public | Flags.Instance )
            .Where( p => p.PropertyType.IsEnum )
            .ForEach( p => Map.Ignore( e => p ) );
    }
}

执行上面的命令会出现以下错误:

System.InvalidOperationException: 
The expression 'e => value(Domain.AbstractMappingProvider`1+<>c__DisplayClass3[Domain.User]).p' is not a valid property expression.
It must be of the form 'e => e.Property'.

如何使用“p”(实际上是“e”的属性)使其不仅可以编译而且可以工作? :o)

我希望有人有一个聪明的技巧来解决这个问题。欢迎使用替代解决方案,但请记住,整个想法是避免为每个枚举属性调用 Map.Ignore。

I am just diving into the use of code-first with CTP5 for Entity Framework. To ease the pain of configuring the database mappings I've created myself a little helper class to serve as the base class for any custom mappings, but I'm unable to figure out how to make the last statement in the method work.

I am locating all public properties of type Enum and then calling the .Ignore method for every property found on the given type. The code uses Fasterflect for reflection and a little ForEach helper, but it should be fairly obvious what the code does.

internal abstract class AbstractMappingProvider<T> : IMappingProvider where T : class
{
    public EntityTypeConfiguration<T> Map { get; private set; }

    public virtual void DefineModel( ModelBuilder modelBuilder )
    {
        Map = modelBuilder.Entity<T>();

        Map.ToTable( typeof(T).Name );

        typeof(T).Properties( Flags.Public | Flags.Instance )
            .Where( p => p.PropertyType.IsEnum )
            .ForEach( p => Map.Ignore( e => p ) );
    }
}

Executing the above gives me the following error:

System.InvalidOperationException: 
The expression 'e => value(Domain.AbstractMappingProvider`1+<>c__DisplayClass3[Domain.User]).p' is not a valid property expression.
It must be of the form 'e => e.Property'.

How can I use the "p" (which is in fact a property on "e") to make this not just compile but also work? :o)

I'm hoping someone has a clever trick to solve this. Alternatives solutions are welcome, but remember that the whole idea is to avoid having to call Map.Ignore for every enumeration property.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

病女 2024-10-28 19:44:48

它使用标准的 .NET 反射库,但我确信您可以根据需要将其转换为 Fasterflect。我已向 AbstractMappingProvider 添加了一个 Ignore 方法,以便我们可以使用 MakeGenericMethod() 在运行时解析属性的泛型类型,以便将此时的 Lambda 强制转换为正确的表达式类型。很可能有更好/更快/更简单的方法来做到这一点。

附带说明一下,我相当确定,在代码第一个候选版本(实体框架 4.1 候选版本的一部分)中,按约定映射时默认情况下已经忽略枚举。

internal abstract class AbstractMappingProvider<T> : IMappingProvider where T : class
{
    public EntityTypeConfiguration<T> Map { get; private set; }

    public virtual void DefineModel(DbModelBuilder modelBuilder)
    {
        Map = modelBuilder.Entity<T>();

        Map.ToTable(typeof(T).Name);

        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.PropertyType.IsEnum);

        var parameterExpression = Expression.Parameter(typeof(T), "e");

        foreach (var propertyInfo in properties)
        {
            // Build up the expression
            var propertyExpression = Expression.Property(parameterExpression, propertyInfo);
            var funcType = typeof (Func<,>).MakeGenericType(typeof (T), propertyInfo.PropertyType);
            var ignoreExpression = Expression.Lambda(funcType, propertyExpression, new[] {parameterExpression});

            // Call the generic Ignore method on this class, passing in the expression
            var ignoreMethod = this.GetType().GetMethod("Ignore");
            var genericIgnoreMethod = ignoreMethod.MakeGenericMethod(propertyInfo.PropertyType);
            genericIgnoreMethod.Invoke(this, new object[]{ignoreExpression});
        }
    }

    public void Ignore<TPropertyType>(LambdaExpression lambdaExpression)
    {
        var expression = (Expression<Func<T, TPropertyType>>) lambdaExpression;
        Map.Ignore(expression);
    }
}

This uses the standard .NET reflection libraries but I'm sure you can convert it to fasterflect if you like. I've added an Ignore method to the AbstractMappingProvider so that we can use MakeGenericMethod() to resolve the generic type for the property at runtime in order to cast the Lambda we have at that point to the correct Expression type. There could well be a better/faster/easier way to do this.

As a side note, I'm fairly sure that in that the code first Release Candidate (part of the Entity Framework 4.1 release candidate), enums are already ignored by default when mapping by convention.

internal abstract class AbstractMappingProvider<T> : IMappingProvider where T : class
{
    public EntityTypeConfiguration<T> Map { get; private set; }

    public virtual void DefineModel(DbModelBuilder modelBuilder)
    {
        Map = modelBuilder.Entity<T>();

        Map.ToTable(typeof(T).Name);

        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.PropertyType.IsEnum);

        var parameterExpression = Expression.Parameter(typeof(T), "e");

        foreach (var propertyInfo in properties)
        {
            // Build up the expression
            var propertyExpression = Expression.Property(parameterExpression, propertyInfo);
            var funcType = typeof (Func<,>).MakeGenericType(typeof (T), propertyInfo.PropertyType);
            var ignoreExpression = Expression.Lambda(funcType, propertyExpression, new[] {parameterExpression});

            // Call the generic Ignore method on this class, passing in the expression
            var ignoreMethod = this.GetType().GetMethod("Ignore");
            var genericIgnoreMethod = ignoreMethod.MakeGenericMethod(propertyInfo.PropertyType);
            genericIgnoreMethod.Invoke(this, new object[]{ignoreExpression});
        }
    }

    public void Ignore<TPropertyType>(LambdaExpression lambdaExpression)
    {
        var expression = (Expression<Func<T, TPropertyType>>) lambdaExpression;
        Map.Ignore(expression);
    }
}
暮色兮凉城 2024-10-28 19:44:48

问题是 P 是一个 PropertyInfo 对象。该类具有有关该属性的元数据,但对分配给各个对象上的属性的值一无所知。您必须利用从 P 获取的属性名称手动创建一个 Expression 对象以传递到 Ignore 方法。

The problems is that P is a PropertyInfo object. That class has metadata about the property but knows nothing about values assigned to the property on various objects. You will have to manually create an Expression object to pass in to the Ignore method based by leveraging the property name that you can get from P.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文