在运行时生成类



我已经为Linq To Sql (L2S)创建了一个更新操作,其工作原理如下:

var rowsaffected = db.Tables.Where(...).Join...Group..
                            .Update(x => new Table { Column = x.Something });

问题是L2S不允许您在查询中创建实体(上面的行在运行时导致异常)。

为了解决这个问题,我创建了一个像这样的非实体类:

class TableUpdate : Table { }

并在Update

中使用它
.Update(x => new TableUpdate { Column = x.Something });

可以正常工作

现在的问题是,如果它是一个好主意,在运行时动态地创建TableUpdate类,只是在将其发送到L2S sql生成器之前将其替换为表达式树?

类永远不会被实例化,所以不需要代码,只需要元数据。

我假设性能不是问题(与实际的数据库更新相比),但是还有其他事情要考虑吗?

  • 可以有名称冲突,如果我创建相同的类几次?
  • 我可以缓存元数据吗?

是这样解决的:

private static readonly Dictionary<Type, Type> _noEntityClasses = new Dictionary<Type, Type>(1);
private static ModuleBuilder _module;
private static Type CreateNoEntityClass(Type entityClass) {
    lock (_noEntityClasses) {
        Type noentityClass;
        if (!_noEntityClasses.TryGetValue(entityClass, out noentityClass)) {
            if (_module == null) {
                var assemblyName = new AssemblyName("LinqToSqlGenerated");
                var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
                _module = assemblyBuilder.DefineDynamicModule("NonEntity");
            }
            var typeBuilder = _module.DefineType(entityClass.Name + "NoEntity", TypeAttributes.Class | TypeAttributes.NotPublic, entityClass);
            noentityClass = typeBuilder.CreateType();
            _noEntityClasses.Add(entityClass, noentityClass);
        }
        return noentityClass;
    }
}
private static IQueryable<T> RemoveEntity<T>(IQueryable<T> source, DataContext context) {
    var mapping = context.Mapping.MappingSource.GetModel(context.GetType());
    var noEntityExpression = source.Expression.Visit<MemberInitExpression>(expression => {
            if (!mapping.GetMetaType(expression.Type).IsEntity)
                return expression;
            return Expression.MemberInit(Expression.New(CreateNoEntityClass(expression.Type)), expression.Bindings);
                                                          });
    return source.Provider.CreateQuery<T>(noEntityExpression);
}

使用RunSharp可以很容易地创建一个从现有类扩展的新类。

您可以创建一个类来创建这些包装类,并跟踪它已经构造了哪些类型的类。可能是Dictionary<Type, Type>,将原始类型链接到动态创建的包装类型。

该类中的静态函数将简单地初始化该包装类型。

public static object ExtendedClassInstance<T>()
{
    Type type = typeof( T );
    if ( !_wrappedTypes.Contains( type ) )
    {
        // Use RunSharp to create the type.
    }
    return Activator.CreateInstance( _wrappedTypes[ type ] );
}

我使用的一种技术是用T4模板生成类似的类。链接到奥列格的博客有一些有用的教程。

从问题描述来看,似乎不需要运行时生成,只需要编译时生成。如果您确实需要运行时,T4将不起作用。

相关内容

  • 没有找到相关文章

最新更新