您可以使用EF Core来实现对外部数据库的使用案例,无需使用ADO.Net,这个解决方案基于@ErikEj提供的针对EF Core的通用解决方案。(请注意,一些函数和命名空间在EF Core 3中已更改,但仍保留在.NET 5+中,但是相同的通用概念仍然适用)
public static IList<T> Query<T>(string connectionString, string query, params object[] parameters) where T : class
{
try
{
using (var contextGeneric = new ContextForQuery<T>(connectionString))
{
return contextGeneric.Query<T>().FromSql(query, parameters).ToList();
}
}
catch (System.Data.SqlClient.SqlException ex)
{
throw new SQLIncorrectException(ex);
}
catch (System.InvalidOperationException ex)
{
throw new NotImplementedException();
}
}
private class ContextForQuery<T> : DbContext where T : class
{
private readonly string connectionString;
public ContextForQuery(string connectionString)
{
this.connectionString = connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString, options => options.EnableRetryOnFailure());
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<T>().HasNoKey();
base.OnModelCreating(modelBuilder);
}
}
因此,使用它需要具体类型定义的支持,为匿名类型添加支持需要更多的努力,但为此创建具体类型并不是坏事,这里的整个重点是尝试让您更加倾向于声明性代码风格,因为它们提高了代码的可读性和检查性,并提供了文档和其他扩展配置,如相关实体。
public class NamedObject
{
public int Id { get; set; }
public string Name { get; set; }
}
...
var connectionString = "Insert your connection string here...";
var data = Query<NamedObject>(connectionString, "SELECT TOP 10 Id, FullName as Name FROM Employee");
foreach (var emp in data)
{
Console.WriteLine(emp.Name);
}
背景
在EF 6(.Net Framework)中,我们可以使用DbContext.Database.FromSQL<T>()
执行即席SQL语句,自动映射到指定类型的T
。由于FromSQL
的结果与EF的其余部分不一致,结果是单个IEnumerable<T>
,因此在EF Core中没有复制此功能。您无法进一步组合此查询以Include()
相关实体,也无法将过滤器添加到基础查询中。
在 EF Core 中,要执行原始 SQL 语句并返回类型
T
,需要在 DbContext 中将其定义为
DbSet<T>
。实际上,这个集合不需要映射到数据库中的任何表格,事实上,自从 EF Core 2.1 开始,我们甚至不需要为此类型指定一个
键。它只是一种预定义期望结构的机制,而不是按需执行 Ad-Hoc 请求,它为您提供了与传统的
FromSQL
相同的功能,但还允许您定义丰富的导航属性集,以便在将您的
RawSQL 插值到 LINQ to SQL 管道后进一步组合查询。
一旦在上下文中定义了类型,只需调用
DbSet<T>.FromSqlRaw()
。不同之处在于,现在我们有了一个
IQueryable<T>
,我们可以使用它来进一步
compose以包含相关实体或应用在数据库内进行评估的筛选器。
此响应中发布的解决方案不允许组合,而是按预期的序列使用 EF 运行时来提供与原始 EF 6 实现相同的行为。
在最新版本的 EF Core 中,并且现在在 .Net 5+ 中需要应用以下微妙的更改:
- Core 2.1:
return contextGeneric.Query<T>().FromSql(query, parameters).ToList();
- Core 3+:
return contextGeneric.Set<T>().FromSqlRaw(query, parameters).ToList();
DbConnection
。 - Chris Schaller