3

我正在尝试通过传入需要水合的子对象的表达式来在存储库中实现一种急切加载功能。

    Candidate Get(int candidateId, params Expression<Func<Candidate, object>>[] includes);

所以我的服务可以这样调用:

        candidateRepository.Get(1, p => p.Notes, p => p.Profile, p => p.Application);

其中 Notes、Profile 和 Application 都是 Candidate 的属性。像这样的东西:

    public class Candidate
    {
        public string Name { get; set; }

        public IList<CandidateNote> Notes { get; set; }

        public Profile Profile { get; set; }

        public Application Application { get; set; }
    }

因此,在存储库中,我需要确定是否将属性传递到表达式参数中以实际尝试对其进行水合。但我没有看到一种优雅的方式来实现这一目标。

    public Candidate Get(int candidateId, params Func<Candidate, object>[] includes)
    {
        ...

        if (candidate.Notes property was specified?)
        {
           candidate.Notes = this.candidateNoteRepository.List(candidateId);
        }

        return candidate;
    }

看起来我可以通过表达式从表达式中获取属性名称(includes[0].Body as MemberExpression).Member.Name,但似乎应该有更简单的方法。另外,我不喜欢字符串比较。我真的不想这样做,除非我必须:

        if (includes[0].Body as MemberExpression).Member.Name == "Notes")
        {

看起来它应该是非常简单的东西

        if (includes[0].Is(candidate.Notes) or includes[0](candidate.Notes).Match())
        {

万一它出现,我非常希望将包含作为表达式数组保留,因为尽管我今天正在使用 ADO.NET,但我们计划最终走实体框架的道路,这些表达式将很好地工作使用 Include 方法。

        return this.Filter(m => m.Candidates.CandiateId == candidateId)
            .Include(includes[0])
4

2 回答 2

1

你可能不想这样做。它将强制您在编译时指定所有属性值,这既乏味又容易出错,而且扩展性也不强。

相反,您最好MemberInfo从表达式中获取对象,然后使用它来获取该成员的值并设置给定对象的该成员的值。

从帮助器开始,MemberInfo按照您显示的模式从表达式中获取对象:

public static MemberInfo GetMemberInfo(LambdaExpression expression)
{
    var body = expression.Body as MemberExpression;
    if (body == null)
        return null;
    else
        return body.Member;
}

然后你可以得到你需要获取的成员对象的集合:

var members = includes.Select(selector => GetMemberInfo(selector))
    .Where(member => member != null)
    //this validates the member is from the type itself; 
    //remove if such validation isn't desired
    .Intersect(typeof(Candidate).GetMembers());

然后通过查询或实际获取数据所需执行的任何其他操作来获取所有这些成员的值。

然后创建新对象并填充每个成员的值:

var newItem = new Candidate();

foreach(var member in members)
{
    //Note that GetValueForMember shouldn't be doing a query.
    //it should be getting getting the value from the results
    member.SetValue(newItem, GetValueForMember(member));
}
于 2013-10-28T15:35:36.980 回答
0

正如您所说:字符串比较不是一个好方法,因为它不容易扩展。您可以更仔细地检查该成员以确定它是否是有效的包含。
一种选择是查看属性的返回类型。如果它是从 IEnumerable 派生的,那么它可能是一个有效的包含。
如果您无法在属性本身中找到必要的事实来做出决定,您可以使用自定义属性来标记类中的包含属性。然后,您可以检查可能包含的 CustomAttributes 属性以确定它是否是有效的包含。

于 2013-10-28T15:20:52.137 回答