实体框架.Include()与编译时检查? [英] Entity Framework .Include() with compile time checking?

查看:101
本文介绍了实体框架.Include()与编译时检查?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码,它调用EF生成的数据上下文:

  var context = new DataContext(); 
var employees = context.Employees.Include(Department);

如果我更改部门关系的名称,那么这段代码将开始引发运行时错误。那么有什么方法可以安全地调用.Include()方法,所以我得到所有被引用的关系的编译时间检查?

解决方案

让moi_meme的想法进一步发展,我的同事开发了以下解决方案,适用于所有情况。他介绍了一种新方法,用于处理一对多和多对多关系的 Includes()。它允许你这样写:

  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))

所有信用额度均来自 https://stackoverflow.com/users/70427/bojan -resnik ,所以去给他一些爱,如果你喜欢解决方案。

  public static class ObjectQueryExtensions 
{
public static ObjectQuery< T>包括< T>(此ObjectQuery< T>查询,Action< IncludeObjectQuery< T>>>动作)
{
var sb = new StringBuilder();
var queryBuilder = new IncludeObjectQuery< T,T>(query,sb);
action(queryBuilder);
return queryBuilder.Query;
}

public static ObjectQuery< TEntity>包含< TEntity,TProperty>(此ObjectQuery< TEntity>查询,表达式< Func< TEntity,TProperty>>表达式)
{
var sb = new StringBuilder();
return IncludeAllLevels(expression,sb,query);
}

static ObjectQuery&TQuery>
{
foreach(expression.GetPropertyLevels()中的var名称)包含所有层次< TEntity,TProperty,TQuery>(表达式< TEntity,TProperty>>表达式,StringBuilder sb,ObjectQuery&TQuery&
{
sb.Append(name);
query = query.Include(sb.ToString());
Debug.WriteLine(string.Format(Include(\{0} \),sb));
sb.Append('。');
}
返回查询;
}

static IEnumerable< string> GetPropertyLevels< TClass,TProperty>(此表达式&FunC< TClass,TProperty>>表达式)
{
var namesInReverse = new List< string>();

var unaryExpression =表达式为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>查询{get;私人集合

public IncludeObjectQuery(ObjectQuery< TQuery> query,StringBuilder builder)
{
_pathBuilder = builder;
Query = query;
}

public IncludeObjectQuery< TQuery,U>包含< U>(表达式< Func< T,U>表达式)
{
Query = ObjectQueryExtensions.IncludeAllLevels(expression,_pathBuilder,Query);
返回新的IncludeObjectQuery< TQuery,U>(Query,_pathBuilder);
}

public IncludeObjectQuery< TQuery,U>其中U:class
{
Query = ObjectQueryExtensions.IncludeAllLevels(expression,_pathBuilder,Query);包含< U>(Expression< Func< T,EntityCollection&
返回新的IncludeObjectQuery< TQuery,U>(Query,_pathBuilder);
}
}
}


Consider the following code, which is calling against an EF generated data context:

var context = new DataContext();
var employees = context.Employees.Include("Department");

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?

解决方案

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")

as this:

context.Customer
    .Include(c => c.Address)
    .Includes(c => c.Include(customer => customer.Orders)
                    .Include(order => order.OrderLines))

All credit goes to https://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()与编译时检查?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆