实体框架IQueryable与poco生成

时间:2014-02-04 23:26:26

标签: c# entity-framework lazy-loading poco iqueryable

我已经创建了一个T4模板,它为每个属性生成标准的Entities类和Interfaces,这样我就可以制作只包含我想要的数据的自定义poco对象。我还创建了一个复制函数,它可以在实现所述实体接口的任何对象之间进行转换

生成的代码如下所示

//------------------------------------------------------------------------------
// <auto-generated>
//    This code was generated from a template.
//
//    Manual changes to this file may cause unexpected behavior in your application.
//    Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace DomainModel
{
    using System;
    using System.Collections.Generic;
    using System.Linq;


    public interface IRole
    {
    }
    public interface IRole_RoleId : IRole
    {
      int RoleId { get; set; }
    }
    public interface IRole_ApplicationName : IRole
    {
      string ApplicationName { get; set; }
    }
    public interface IRole_RoleName : IRole
    {
      string RoleName { get; set; }
    }
    public interface IRole_Description : IRole
    {
      string Description { get; set; }
    }

    public interface IRole_Users : IRole 
    {
      ICollection<IUser> Users { get; set; }
      IUser NewUsers();
    }

    public interface IRole__All : IRole_RoleId, 
      IRole_ApplicationName, 
      IRole_RoleName, 
      IRole_Description, 
      IRole_Users
    {
    }

    public partial class Role : IRole
    {
      public Role()
      {
        this.Users = new HashSet<User>();
      }

      public int RoleId { get; set; }
      public string ApplicationName { get; set; }
      public string RoleName { get; set; }
      public string Description { get; set; }

      public virtual ICollection<User> Users { get; set; }
    }

    public static class IRoleExt
    {
      public static T CopyTo<T>(this IRole src , T dest = null  )  where T : class, IRole, new()
      {
        dest = dest ?? new T();
        dest.Copy(src);
        return dest;
      }
      public static void Copy(this IRole dest, IRole src)
      {
        var ms = new MergeStack();
        Role role;
        if((role = dest as Role) != null){
          ms.TryCopy<IRole,Role>((indexCopy) => {return indexCopy(role);}, src);
        }
        else if ((role = src as Role) != null){
          ms.TryCopy<Role,IRole>((indexCopy) => {return indexCopy(dest);}, role);
        }
        else{
          ms.TryCopy<IRole,IRole>((indexCopy) => {return indexCopy(dest);}, src);
        }
        dest.Copy(src, ms);
      }

      internal static void Copy(this IRole dest,
        IRole src,
        MergeStack ms)
      {
        dest.Set_RoleId(src.Get_RoleId());
        dest.Set_ApplicationName(src.Get_ApplicationName());
        dest.Set_RoleName(src.Get_RoleName());
        dest.Set_Description(src.Get_Description());
        dest.Set_Users(src.Get_Users(),ms);
      }
        public static Nullable<int> Get_RoleId(this IRole src)
      {
        IRole_RoleId srcIRole_RoleId;
        if((srcIRole_RoleId = src as IRole_RoleId) != null )
        {
          return srcIRole_RoleId.RoleId;
        }
        Role role;
        if((role = src as Role) != null )
        {
          return role.RoleId;
        }
          return null;

      }
        public static void Set_RoleId(this IRole dest, Nullable<int> src)
      {
        IRole_RoleId destIRole_RoleId;
        if((destIRole_RoleId = dest as IRole_RoleId) != null)
        {
           destIRole_RoleId.RoleId = src.GetValueOrDefault();
            }
        Role role;
        if((role = dest as Role) != null )
        {
          role.RoleId = src.GetValueOrDefault();
        }
      }

        public static string Get_ApplicationName(this IRole src)
      {
        IRole_ApplicationName srcIRole_ApplicationName;
        if((srcIRole_ApplicationName = src as IRole_ApplicationName) != null )
        {
          return srcIRole_ApplicationName.ApplicationName;
        }
        Role role;
        if((role = src as Role) != null )
        {
          return role.ApplicationName;
        }
          return null;

      }
        public static void Set_ApplicationName(this IRole dest, string src)
      {
        IRole_ApplicationName destIRole_ApplicationName;
        if((destIRole_ApplicationName = dest as IRole_ApplicationName) != null)
        {
           destIRole_ApplicationName.ApplicationName = src;
            }
        Role role;
        if((role = dest as Role) != null )
        {
          role.ApplicationName = src;
        }
      }

        public static string Get_RoleName(this IRole src)
      {
        IRole_RoleName srcIRole_RoleName;
        if((srcIRole_RoleName = src as IRole_RoleName) != null )
        {
          return srcIRole_RoleName.RoleName;
        }
        Role role;
        if((role = src as Role) != null )
        {
          return role.RoleName;
        }
          return null;

      }
        public static void Set_RoleName(this IRole dest, string src)
      {
        IRole_RoleName destIRole_RoleName;
        if((destIRole_RoleName = dest as IRole_RoleName) != null)
        {
           destIRole_RoleName.RoleName = src;
            }
        Role role;
        if((role = dest as Role) != null )
        {
          role.RoleName = src;
        }
      }

        public static string Get_Description(this IRole src)
      {
        IRole_Description srcIRole_Description;
        if((srcIRole_Description = src as IRole_Description) != null )
        {
          return srcIRole_Description.Description;
        }
        Role role;
        if((role = src as Role) != null )
        {
          return role.Description;
        }
          return null;

      }
        public static void Set_Description(this IRole dest, string src)
      {
        IRole_Description destIRole_Description;
        if((destIRole_Description = dest as IRole_Description) != null)
        {
           destIRole_Description.Description = src;
            }
        Role role;
        if((role = dest as Role) != null )
        {
          role.Description = src;
        }
      }

      public static ICollection<IUser> Get_Users(this Role src)
      {
        return src.Users.Cast<IUser>().ToList();
        }
        public static ICollection<IUser> Get_Users(this IRole src)
      {
        IRole_Users srcIRole_Users;
        if((srcIRole_Users = src as IRole_Users) != null )
        {
          return srcIRole_Users.Users;
        }
        Role role;
        if((role = src as Role) != null )
        {
          return role.Get_Users();
        }
          return null;
      }
      public static void Set_Users(this IRole dest, ICollection<IUser> src)
      {
        var ms = new MergeStack();
        dest.Set_Users(src, ms);
      }

      internal static void Set_Users(this IRole dest, ICollection<IUser> src, MergeStack ms)
      {
        IRole_Users destIRole_Users;
        if((destIRole_Users = dest as IRole_Users) != null)
        {
          Func<IUser,IUser> iToIFunc = (x=> 
              ms.TryCopy<IUser,IUser>((indexCopy)=>
              {
                var ret = destIRole_Users.NewUsers();
                  var exists = indexCopy(ret);
                if(null != exists)
                    ret = exists;
                  else
                  ret.Copy(x,ms);
                return ret;
              },x));
          destIRole_Users.Users = (null !=src)?
          src.Select(iToIFunc).ToList():null;
        }

        Role role;
        if((role = dest as Role) != null)
        {
          Func<IUser,User> iToEFunc = (x=> 
              ms.TryCopy<IUser,User>((indexCopy)=>
              {
                var ret = new User();
                  var exists = indexCopy(ret);
                if(null != exists)
                    ret = exists;
                  else
                  ret.Copy(x,ms);
                return ret;
              },x));
          role.Users = (null !=src)?
          src.Select(iToEFunc).ToList():null;
        }
      }
    }
}

你看到的合并堆栈对象是一个跟踪器,所以我可以处理引用循环。看起来像这样

using System;
using System.Collections.Generic;
using System.Linq;

namespace DomainModel
{

    internal class MergeStack
    {
        private readonly Dictionary<Type, Dictionary<Object, Object>> _mergeObjDict = new Dictionary<Type, Dictionary<object, object>>();
        private readonly IList<Action> _registerActions = new List<Action>();

        public T TryCopy<TKey, T>(Func<Func<T, T>, T> func, TKey key) where T : class
        {
            if (key == null)
                return null;

            Func<T, T> act = (objToIndex) =>
            {
                Dictionary<object, object> objToObj;
                if (!_mergeObjDict.ContainsKey(objToIndex.GetType()))
                {
                    objToObj = new Dictionary<object, object>();
                    _mergeObjDict.Add(objToIndex.GetType(), objToObj);
                }
                else
                {
                    objToObj = _mergeObjDict[objToIndex.GetType()];
                }
                if (!objToObj.ContainsKey(key))
                {
                    objToObj.Add(key, objToIndex);
                }
                else
                {
                    return objToObj[key] as T;
                }
                return null as T;
            };
            return func(act);
        }
    }
}

现在所有这些都按预期工作正常,它成功地将所有已实现的属性复制到域模型/接口和从域模型/接口复制。

我现在正试图通过IQueryable和延迟加载来玩得很好。

现在我正在这样做

dbContext.Roles.Select((x)=> x.CopyTo<RolesPoco>());

我想知道是否有一种方法可以自动生成包括

在内的内容
dbContext.Roles.Select((x)=> x.Users.Include((y)=> y.someSubEntity);

我还想看看我是否可以加上像这样的条款

//the first string is a path so something like "Roles.Users.someSubEntity"
//the second string is a IQueryable function like Where or Take
Dictionary<String,Dictionary<String,List<Func<T, IQueryable<TProperty>>>> queryDict

dbContext.Roles.Select((x)=> x.CopyTo<RolesPoco>(queryDict)

然后List会是一些lambdas列表,可以在include函数中运行。 有人对此有什么想法吗?

编辑:我重构了一些简化的代码,以便即使该类没有实现接口也可以调用getter / setter。因此,无论是否存在支持字段,都可以访问属性。如果未定义,则返回null。

Edit2 :由于我似乎不清楚我想要实现的目标,让我澄清一下。如果你转到这个msdn page的备注部分,你会看到一些select语句。我想生成那些表达式,然后根据被复制的类是否包含实现该成员的接口在父选择中使用它们。我正在避免使用linqToObject,因为我只需要在CopyTo中定义的属性,但是导航属性是接口,它会炸毁实体框架。这是为了延迟加载目的。 MergeStack将组合并在树上返回这些表达式。我从a DaedTech blogpost

得到了这个想法

1 个答案:

答案 0 :(得分:0)

Roles是IQueryable,因此您需要从Queryable扩展类中获取Select方法。 您还需要从Enumerable扩展类中获取Include。 然后,您需要使用Role作为通用参数来调用Select方法。 您需要使用Expression.Lambda,Expression.Call和Expression.Property构建lambda。