我正在尝试将我的域模型直接映射到 EF。为此,我在我的模型中引入了一个私有(private)属性,如下所示:
private ICollection<Tag> TagsInternal { get; set; }
public Article(Guid id, ... , IEnumerable<Tag> tags) : base(id)
{
...
this.TagsInternal = new List<Tag>(tags.Where(i => i != null));
}
public IEnumerable<Tag> Tags { get { return this.TagsInternal.AsEnumerable(); } }
为了让 EF 访问“支持属性”,我添加了一些扩展方法:
public static class FluentApiExtensions
{
public static ManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType>
HasMany<TEntityType, TTargetEntityType>(this EntityTypeConfiguration<TEntityType> mapper,
string propertyName)
where TEntityType : class
where TTargetEntityType : class
{
var lambda = GetLambdaExpression<TEntityType>(propertyName);
return mapper
.HasMany((Expression<Func<TEntityType, ICollection<TTargetEntityType>>>)lambda);
}
public static ManyToManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType>
WithMany<TEntityType, TTargetEntityType>(this ManyNavigationPropertyConfiguration<TEntityType, TTargetEntityType> mapper,
string fieldName)
where TEntityType : class
where TTargetEntityType : class
{
var lambda = GetLambdaExpression<TTargetEntityType>(fieldName);
return mapper
.WithMany((Expression<Func<TTargetEntityType, ICollection<TEntityType>>>)lambda);
}
private static LambdaExpression GetLambdaExpression<T>(string propertyName)
{
var type = typeof (T);
var parameterExpression = Expression.Parameter(type, "type");
var expression = (Expression)parameterExpression;
var propertyInfo = type
.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (propertyInfo == null)
throw new ArgumentException(string.Format("There is no property named '{0}' on type '{1}'.",
propertyName, type.Name));
var propertyExpression = Expression.Property(expression, propertyInfo);
return Expression.Lambda(propertyExpression, parameterExpression);
}
}
然后我就可以像这样获取导航属性:
public Maybe<Article> GetArticle(Guid articleId)
{
articleId.MustNotBeNull();
var article = this.unitOfWork.Context.Articles
.Include("TagsInternal")
.FirstOrDefault(a => a.Id == articleId);
return article == null
? new Maybe<Article>()
: new Maybe<Article>(article);
}
但是,例如,当尝试执行在其 where 子句中包含“标签”的查询时,整个事情就崩溃了
var test = this.unitOfWork.Context.Articles
.Where(a => a.Tags.Count() > 0);
消息是
LINQ to Entities 不支持指定的类型成员“Tags”。仅支持初始化器、实体成员和实体导航属性。
有什么办法可以补救吗?我正在认真考虑将 EF 排除在模型和映射之外,或者按照 Vaughn Vernon 的建议沿着状态对象路线走。
最佳答案
您说您正在将域模型映射到 EF。因此,考虑到这一点,您将希望让您的 EF 类尽可能简单。它们的存在只是为了持久化您的域模型。这意味着:
- 不要将方法放在 EF 类上。
- 不要使用默认构造函数以外的任何东西。
- 只使用公共(public)方法。
- 手动将域类映射到 EF 类或使用类似 AutoMapper 的东西.
此外,根据您上面的代码,您似乎有自己的 UnitOfWork 实现。这是不必要的 DbContext
是工作单元。 (使用您的 DI 容器来管理 DbContext
session 。如果这是一个 Web 应用程序,您可能希望它们具有每个请求的生命周期。)
我也不确定你为什么要回来 Maybe<Article>
多于。如果没有找到,就返回null。在你的 Controller 中,如果 GetArticle()
返回 null
, 然后返回 HttpNotFound()
来自 Controller 。
如果执行上述操作,应该会消除混淆并删除上面的大量映射代码。
关于c# - 有没有办法在 where 子句中访问私有(private)属性(property)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30827666/