0

我正在考虑从运行时动态生成 EntityTypeConfiguration 并且我不希望模型中有任何 EF 依赖项[这就是我避免数据注释的原因]。

所以我声明了一个自定义属性(或者以后可以是任何配置文件)

[AttributeUsage(AttributeTargets.Property, AllowMultiple=true )]
public class PersistableMemberAttribute : Attribute
{
    public bool Iskey;
    public bool IsRequired;
    public bool IsIgnored;
    public bool IsMany;
    public string HasForeignKey;
    public bool PropertyIsRequired;
    public bool PropertyIsOptional;
}

这是我的一个模型的样子:

 public class Blog
{
    [PersistableMember(Iskey=true)]
    public Guid BlogId { get; set; }

    [PersistableMember(PropertyIsRequired = true)]
    public string Name { get; set; }

    public string Url { get; set; }

    [PersistableMember(IsIgnored=true)]        
    public int Rating { get; set; }

    [PersistableMember(IsMany =true)]
    public ICollection<Post> Posts { get; set; }
}

现在我要编写一个通用的 EntityTypeConfiguration ,它将根据属性值在运行时动态创建配置:

 public class GenericEntityConfiguration<T> : EntityTypeConfiguration<T> where T : class
{
    public GenericEntityConfiguration()
    {
        var members = typeof(T).GetProperties();
        if (null != members)
        {
            foreach (var property in members)
            {
                var attrb= property.GetCustomAttributes(typeof( PersistableMemberAttribute ),false).OfType<PersistableMemberAttribute>();
                if (attrb != null && attrb.Count() > 0)
                {
                    foreach (var memberAttributute in attrb)
                    {
                        if (memberAttributute.Iskey || memberAttributute.IsIgnored)
                        {
                            var entityMethod = this.GetType().GetMethod("Setkey");
                            entityMethod.MakeGenericMethod(property.PropertyType)
                              .Invoke(this, new object[] { property, memberAttributute });
                        }

                        if (memberAttributute.IsRequired)
                        {
                            var entityMethod = this.GetType().GetMethod("SetRequired");
                            entityMethod.MakeGenericMethod(property.PropertyType)
                              .Invoke(this, new object[] { property, memberAttributute });
                        }

                        if (memberAttributute.PropertyIsRequired || memberAttributute.PropertyIsOptional)
                        {
                            var entityMethod = this.GetType().GetMethod("SetPropertyConfiguration");
                            entityMethod.MakeGenericMethod(property.PropertyType)
                              .Invoke(this, new object[] { property, memberAttributute });
                        }
                    }
                }
            }
        }

    }

    public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
    {
        var functorParam = Expression.Parameter(typeof(T));
        var lambda = Expression.Lambda(
            Expression.Property(functorParam, propertyInfo)
        , functorParam);

        if (attribute.PropertyIsRequired)
        {
            this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
        }
        if (attribute.PropertyIsOptional)
        {
            this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();

        }
    }

    public void Setkey<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
    {
        var functorParam = Expression.Parameter(typeof(T));
        var lambda = Expression.Lambda(
            Expression.Property(functorParam, propertyInfo)
        , functorParam);

        if (attribute.Iskey)
        {
            this.HasKey<TResult>((Expression<Func<T,TResult>>)lambda);
        }
        if (attribute.IsIgnored)
        {
            this.Ignore<TResult>((Expression<Func<T, TResult>>)lambda);
        }
    }

    public void SetRequired<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) where TResult : class
    {
        var functorParam = Expression.Parameter(typeof(T));
        var lambda = Expression.Lambda(
            Expression.Property(functorParam, propertyInfo)
        , functorParam);
        if (attribute.IsRequired)
        {
            this.HasRequired<TResult>((Expression<Func<T, TResult>>)lambda);
        }
    }

}

但我得到了编译错误

错误 1 ​​类型“TResult”必须是不可为空的值类型,才能在泛型类型或方法“System.Data.Entity.ModelConfiguration.Configuration.StructuralTypeConfiguration.Property(System.Linq. Expressions.Expression>)' D:\R&D\UpdateStorePOC\UpdateStorePOC\Data\GenericEntityConfiguration.cs 63 17 UpdateStorePOC

这对于这两个语句:

        this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();

        this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();

这意味着我需要对我的方法施加约束以将其限制为值类型。在 C# 中,这是通过 'struct' 关键字完成的。

public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) Where TResult : struct

但它不是解决方案,因为我的属性类型可以是一个类,例如 string 或 int、bool double 等。所以完全不清楚我是否可以将它们发送到这种方法中。请帮助我解决这个问题是否有任何其他方法可以做到这一点。

4

1 回答 1

0

我不希望模型中有任何 EF 依赖项。

有了流畅的映射,您就快到了,而且您不会再靠近了。您的属性,即使打算移动到配置文件,也不会使您的模型不再有任何 EF 占用空间。1更糟糕的是,他们只在您的模型和 EF 的映射之间添加了第二个映射层(如果您愿意)。我只看到缺点:

  • 您仍然需要维护模型的元数据,可能不亚于常规的流畅映射和(可能)在没有编译时检查的情况下手动编辑的笨拙 XML。
  • 您将继续扩展您的代码以涵盖 EF 的映射涵盖但您的尚未涵盖的情况。2所以这是浪费精力:到头来你基本上会重写 EF 的映射方法。
  • 当你想升级 EF 时,你必须保持双手交叉。
  • 遇到错误/问题,您只能靠自己:很难获得社区的支持。

所以我对你的问题的回答可以帮助我解决这个问题:使用开箱即用的流畅映射。把事情简单化。


1例如,您仍然必须使用virtual修饰符来启用代理以进行延迟加载。

2像对继承的支持、未映射的外键、最大长度、db 数据类型……这可能会持续一段时间。

于 2012-11-18T01:14:08.323 回答