问题描述
考虑以下code,该呼吁针对EF生成的数据方面:
Consider the following code, which is calling against an EF generated data context:
var context = new DataContext();
var employees = context.Employees.Include("Department");
如果我更改系关系的名字,那么这个code将开始抛出运行时错误。那么,有没有办法来调用一个安全的方式.INCLUDE()方法,所以我得到的编译时间检查所引用的所有关系?
If I change the name of the Department relationship then this code is going to start throwing a runtime error. So is there any way to call the .Include() method in a safe manner, so I get compile time checking for all the relationships being referenced?
推荐答案
以moi_meme的想法更进了一步,我的同事开发了以下解决方案,它在所有情况下工作。他介绍caled的新方法包括()
处理一个一对多和多对多的一对多关系。它可以让你写这篇文章:
Taking moi_meme's idea a step further, my colleague developed the following solution that works in all cases. He introduced a new method caled Includes()
for dealing with one-to-many and many-to-many relationships. It allows you to write this:
context.Customer
.Include("Address")
.Include("Orders")
.Include("Orders.OrderLines")
,如下:
context.Customer
.Include(c => c.Address)
.Includes(c => c.Include(customer => customer.Orders)
.Include(order => order.OrderLines))
一切归功于http://stackoverflow.com/users/70427/bojan-resnik,所以要多给他一些爱,如果你喜欢的解决方案。
All credit goes to http://stackoverflow.com/users/70427/bojan-resnik, so go give him some love if you like the solution.
public static class ObjectQueryExtensions
{
public static ObjectQuery<T> Includes<T>(this ObjectQuery<T> query, Action<IncludeObjectQuery<T, T>> action)
{
var sb = new StringBuilder();
var queryBuilder = new IncludeObjectQuery<T, T>(query, sb);
action(queryBuilder);
return queryBuilder.Query;
}
public static ObjectQuery<TEntity> Include<TEntity, TProperty>(this ObjectQuery<TEntity> query, Expression<Func<TEntity, TProperty>> expression)
{
var sb = new StringBuilder();
return IncludeAllLevels(expression, sb, query);
}
static ObjectQuery<TQuery> IncludeAllLevels<TEntity, TProperty, TQuery>(Expression<Func<TEntity, TProperty>> expression, StringBuilder sb, ObjectQuery<TQuery> query)
{
foreach (var name in expression.GetPropertyLevels())
{
sb.Append(name);
query = query.Include(sb.ToString());
Debug.WriteLine(string.Format("Include(\"{0}\")", sb));
sb.Append('.');
}
return query;
}
static IEnumerable<string> GetPropertyLevels<TClass, TProperty>(this Expression<Func<TClass, TProperty>> expression)
{
var namesInReverse = new List<string>();
var unaryExpression = expression as UnaryExpression;
var body = unaryExpression != null ? unaryExpression.Operand : expression.Body;
while (body != null)
{
var memberExpression = body as MemberExpression;
if (memberExpression == null)
break;
namesInReverse.Add(memberExpression.Member.Name);
body = memberExpression.Expression;
}
namesInReverse.Reverse();
return namesInReverse;
}
public class IncludeObjectQuery<TQuery, T>
{
readonly StringBuilder _pathBuilder;
public ObjectQuery<TQuery> Query { get; private set; }
public IncludeObjectQuery(ObjectQuery<TQuery> query, StringBuilder builder)
{
_pathBuilder = builder;
Query = query;
}
public IncludeObjectQuery<TQuery, U> Include<U>(Expression<Func<T, U>> expression)
{
Query = ObjectQueryExtensions.IncludeAllLevels(expression, _pathBuilder, Query);
return new IncludeObjectQuery<TQuery, U>(Query, _pathBuilder);
}
public IncludeObjectQuery<TQuery, U> Include<U>(Expression<Func<T, EntityCollection<U>>> expression) where U : class
{
Query = ObjectQueryExtensions.IncludeAllLevels(expression, _pathBuilder, Query);
return new IncludeObjectQuery<TQuery, U>(Query, _pathBuilder);
}
}
}
这篇关于实体框架.INCLUDE()与编译时检查?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!