我正在考虑从运行时动态生成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)中将其用作参数'T' .Linq.Expressions.Expression&gt;)'D:\ R&amp; 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等。所以我完全不清楚我是否可以将它们发送到这种方法中。无论是否有其他办法,请帮助我解决这个问题。
答案 0 :(得分:0)
我不希望模型中有任何EF依赖。
通过流畅的映射,你几乎就在那里,你不会再靠近了。您的属性即使打算移动到配置文件,也不会使您的模型不再具有任何EF足迹。 1 更糟糕的是,它们只添加了第二个映射层(如果您愿意)您的模型和EF的映射之间。我只看到了缺点:
所以我对你的问题帮助我解决这个问题的答案将是:使用开箱即用的流畅映射。保持简单。
1 例如,您仍然必须使用virtual
修饰符来启用延迟加载的代理。
2 支持继承,未映射的外键,最大长度,db数据类型......这可能会持续一段时间。