简体   繁体   中英

Entity framework IQueryable with poco generation

I've created a T4 template which generates standard Entities classes along with Interfaces for each of their properties so that I can make customized poco objects containing only the data that I want. I've also created a copy function which can convert between any of the objects which implement said entity's interface

The generated code looks like this

//------------------------------------------------------------------------------
// <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;
        }
      }
    }
}

That merge stack object you see is a tracker so I can handler reference loops. it looks like this

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

Now all this works fine as intended, it successfully copies over all implemented properties to and from the domain model/interface.

I'm now trying to make play nice with IQueryable and lazy loading.

Right now I'm doing this

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

I'd like to see if there's a way I could auto generate includes such as

dbContext.Roles.Select((x)=> x.Users.Include((y)=> y.someSubEntity);

I'd also like to see if I could put on some where clauses like this

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

And then the List would be some list of lambdas that can run inside of the include functions. Anybody have any ideas on this?

Edit : I refactored simplified some of the code so that it could call a getter/setter even if the class didn't implement the interface. So the properties can be accessed regardless of there being a backing field. It returns null if it's not defined.

Edit2 : Since it seems unclear what I'm trying to achieve, let me clarify. If you go down to the remarks part of this msdn page , you'll see some select statements. I want to generate those Expressions and then use them inside of a parent select based on whether or not the class being copied to contains the interface that implements that member. I'm avoiding linqToObject because I only need the properties defined in the CopyTo, but the Navigation properties are interfaces, which blows up entity framework. This is for Lazy loading purposes. MergeStack would be composing and returning those expressions up the tree. I got the idea from a DaedTech blogpost

Roles is IQueryable, so you need to get the Select method from the Queryable extensions class. You also need to get the Include from the Enumerable extension class. You then need to invoke the Select method using Role as a generic argument. You need to construct a lambda using Expression.Lambda, Expression.Call and Expression.Property.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM