C# - 选择“实体和变量 LINQ/查询”
本文关键字:LINQ 实体和变量 查询 变量 选择 实体 | 更新日期: 2023-09-27 18:33:47
我正在使用 C# 构建文件下载服务 - 该过程的一部分验证从一个或多个数据库下载并提供下载的详细信息。
验证过程可以调用四个数据库 - 这实际上取决于下载用于哪个服务。数据库是 MSSQL 或 MySQL,可以使用存储过程(复杂类型(或具有多个联接的 LINQ 查询。所有结果将包含相同的列信息。
我已经在实体框架中定义了数据库,我对单个实例中的代码感到满意 - 如果我查询其他数据库,我不想再次编写执行相同任务的代码。
我已经搜索了几个小时,试图找到一个解决方案,使我能够根据条件指定要使用的实体和查询,并保持其强类型。
对于存储过程查询,我使用如下代码:
using (myEntity1 ctx = new myEntity1())
{
var results = ctx.MyStoredProcedure(param1, param2);
foreach (var result in results)
{
// do stuff here
}
}
对于 LINQ 查询,我可以使用如下代码:
using (myEntity2 ctx = new myEntity2())
{
var results = (from t in ctx.table select new { t.Col1, t.Col2,});
foreach (var result in results)
{
// do stuff here
}
}
简而言之,我希望能够根据许多条件指定实体和查询。我还希望结果是强类型的。这似乎很简单,但我找不到有效的答案。
谢谢
克里斯
经过一年的不间断学习,如果我现在这样做,我可能会使用存储库将每个数据集加载到其 POCO 中,然后将这些 POCO 投影到我真正想要的数据集中,也许使用以下扩展方法:
public static class QueryableExtensions
{
public static ProjectionExpression<TSource> Project<TSource>(this IQueryable<TSource> source)
{
return new ProjectionExpression<TSource>(source);
}
public static string GetSQL<TSource>(this IQueryable<TSource> source)
{
return source.ToString();
}
}
public class ProjectionExpression<TSource>
{
private static readonly Dictionary<string, Expression> ExpressionCache = new Dictionary<string, Expression>();
private readonly IQueryable<TSource> _source;
public ProjectionExpression(IQueryable<TSource> source)
{
_source = source;
}
public IQueryable<TDest> To<TDest>()
{
var queryExpression = GetCachedExpression<TDest>() ?? BuildExpression<TDest>();
return _source.Select(queryExpression);
}
private static Expression<Func<TSource, TDest>> GetCachedExpression<TDest>()
{
var key = GetCacheKey<TDest>();
return ExpressionCache.ContainsKey(key) ? ExpressionCache[key] as Expression<Func<TSource, TDest>> : null;
}
private static Expression<Func<TSource, TDest>> BuildExpression<TDest>()
{
var sourceProperties = typeof(TSource).GetProperties();
var destinationProperties = typeof(TDest).GetProperties().Where(dest => dest.CanWrite);
var parameterExpression = Expression.Parameter(typeof(TSource), "src");
var bindings = destinationProperties
.Select(destinationProperty => BuildBinding(parameterExpression, destinationProperty, sourceProperties))
.Where(binding => binding != null);
var expression = Expression.Lambda<Func<TSource, TDest>>(Expression.MemberInit(Expression.New(typeof(TDest)), bindings), parameterExpression);
var key = GetCacheKey<TDest>();
ExpressionCache.Add(key, expression);
return expression;
}
private static MemberAssignment BuildBinding(Expression parameterExpression, MemberInfo destinationProperty, IEnumerable<PropertyInfo> sourceProperties)
{
var sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == destinationProperty.Name);
if (sourceProperty != null)
{
return Expression.Bind(destinationProperty, Expression.Property(parameterExpression, sourceProperty));
}
var propertyNames = SplitCamelCase(destinationProperty.Name);
if (propertyNames.Length == 2)
{
sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == propertyNames[0]);
if (sourceProperty != null)
{
var sourceChildProperty = sourceProperty.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[1]);
if (sourceChildProperty != null)
{
return Expression.Bind(destinationProperty, Expression.Property(Expression.Property(parameterExpression, sourceProperty), sourceChildProperty));
}
}
}
return null;
}
private static string GetCacheKey<TDest>()
{
return string.Concat(typeof(TSource).FullName, typeof(TDest).FullName);
}
private static string[] SplitCamelCase(string input)
{
return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim().Split(' ');
}
}
http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code