Asp.net core 具有自定义模型的实体框架核心原始SQLQueries

Asp.net core 具有自定义模型的实体框架核心原始SQLQueries,asp.net-core,entity-framework-core,asp.net-core-2.0,Asp.net Core,Entity Framework Core,Asp.net Core 2.0,使用EntityFramework6,我能够使用执行原始SQL查询,并使用DBContext中未定义的自定义模型来存储查询的输出。下面是一个简单的例子: List<MyModel> data = context.Database.SqlQuery<MyModel>("SELECT Orders.OrderID, Customers.CustomerName FROM Orders INNER JOIN Customers ON Orders.CustomerID=Cust

使用EntityFramework6,我能够使用执行原始SQL查询,并使用DBContext中未定义的自定义模型来存储查询的输出。下面是一个简单的例子:

List<MyModel> data = context.Database.SqlQuery<MyModel>("SELECT Orders.OrderID, Customers.CustomerName FROM Orders INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;").ToList();
此查询通知EntityFramework核心,查询将返回一个图书列表。有没有一种方法可以在Entity Framework Core中实现类似的功能?

来自.NET Core 2.1:

  • modelBuilder.Query()

  • 使用
    context.Query().FromSql(rawSql)
    获取数据


  • 问题是关于.NETCore2的。现在我有了一个解决方案,我将把它写在这里,以便其他人可以使用它,以防他/她需要它

    首先,我们在dbContext类中添加以下方法

    public List<T> ExecSQL<T>(string query)
    {
        using (var command = Database.GetDbConnection().CreateCommand())
        {
            command.CommandText = query;
            command.CommandType = CommandType.Text;
            Database.OpenConnection();
    
            List<T> list = new List<T>();
            using (var result = command.ExecuteReader())
            {
                T obj = default(T);
                while (result.Read())
                {
                    obj = Activator.CreateInstance<T>();
                    foreach (PropertyInfo prop in obj.GetType().GetProperties())
                    {
                        if (!object.Equals(result[prop.Name], DBNull.Value))
                        {
                            prop.SetValue(obj, result[prop.Name], null);
                        }
                    }
                    list.Add(obj);
                }
            }
            Database.CloseConnection();
            return list;
        }
    }
    
    公共列表ExecSQL(字符串查询)
    {
    使用(var command=Database.GetDbConnection().CreateCommand())
    {
    command.CommandText=查询;
    command.CommandType=CommandType.Text;
    OpenConnection();
    列表=新列表();
    使用(var result=command.ExecuteReader())
    {
    T obj=默认值(T);
    while(result.Read())
    {
    obj=Activator.CreateInstance();
    foreach(obj.GetType().GetProperties()中的PropertyInfo属性)
    {
    如果(!object.Equals(结果[prop.Name],DBNull.Value))
    {
    属性设置值(对象,结果[属性名称],null);
    }
    }
    列表。添加(obj);
    }
    }
    CloseConnection();
    退货清单;
    }
    }
    
    现在我们可以得到以下代码

    List<Customer> Customers = _context.ExecSQL<Customer>("SELECT ......");
    
    List Customers=\u context.ExecSQL(“选择…”);
    
    以下是我是如何让它工作的(为了完整性):

    MyModel.cs:

    公共类MyModel
    {
    //SQL将返回的列
    公共双精度?A{get;set;}
    公共双精度B{get;set;}
    }
    
    添加刚从原始EF上下文类继承的类(我称为My DbContextBase):

    公共类DbContext:DbContextBase
    {
    公共虚拟数据库集MyModels{get;set;}
    模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
    {
    基于模型创建(modelBuilder);
    //必要,因为我们的模型不是EF模型
    modelBuilder.Entity(Entity=>
    {
    entity.HasNoKey();
    });
    }
    }
    
    使用该类(而不是原始EF上下文类):

    //使用新的db子类
    使用(var db=new DbContext())
    {
    var models=await db.MyModels.FromSqlRaw(…).ToListSync();//例如:“从苹果A选择*在A.col=B.col上加入香蕉B”
    }
    
    注:

    • 如果需要,只需使用
      FromSqlInterpolated
      而不是
      FromSqlRaw
    • “db context”子类允许您在不影响“polyfill”代码的情况下更新EF模型
    • 使用仅返回1个结果集的SQL Server存储过程
    遵循以下步骤:

    创建您的模型 如果您可以将其简化为尽可能通用的模型,可能会更好,但这不是必须的:

    public class MyCustomModel
    {
       public string Text { get; set; }
       public int Count { get; set; }
    }
    
    将其添加到您自己的DbContext中 为您的自定义模型创建
    DbSet

    public virtual DbSet<MyCustomModel> MyCustomModelName { get; set; }
    
    公共虚拟数据库集MyCustomModelName{get;set;}
    请记住,指定自定义模型没有键

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        ...
    
        modelBuilder.Entity<MyCustomModel>().HasNoKey();
    }
    
    模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
    {
    基于模型创建(modelBuilder);
    ...
    modelBuilder.Entity().HasNoKey();
    }
    
    从dbContext实例中使用它 异步公共任务GetMyCustomData() { var rv=新列表(); 使用(var dataContext=new DbContext()) { var sql=@” 选择文本字段为“文本”,计数(1)为“计数” 来自MyTable”; rv=wait dataContext.Set().FromSqlRaw(sql).toListSync(); } 返回rv; }
    还没有。最终将有可能在未来的EFC版本中发布。请参阅和。谢谢您的回复。所以我不得不等待这个未来。更多关于这个特性的信息在这里:这只是普通的ADO.Net。这并不是说它不起作用,而是我想知道为什么在EF core现在有内置解决方案的情况下,您会提出它。添加generic Activator.CreateInstance()的速度非常慢,如果查询大型数据集,它会快速复合。如果您追求的是性能,请查看Dapper以获得完整的解决方案,或者从DbDataReader手动创建模型实例(不太好)。整个应用程序都基于EF,因此我必须使用EF。我知道大量记录的问题,但我们在所有查询中都使用分页,因此不可能有超过100条记录。答案不值得向下投票=)基本上EF中缺少自定义查询支持。core,我们的架构中有外部视图,我们在其上执行连接和自定义查询,我们不能只添加自定义数据库集,因为它不受支持,所以我们使用simular,只使用automapper和更好的缓存解决方案。这个解决方案的问题是缺少缓存,比如getProperties相当重,您可以用编译后的表达式替换ActivatorCreateInstance。AutoMapper基本上已经完成了所有的脏活。谢谢,但这不会导致数据库中的表基于
    YourModel
    生成吗?我有一个带有productname和quantity的自定义类。使用与在EF5.x中有效的提问相同的技巧。我在.Net标准2.0类库中有EF核心:-SHad想修改我的问题但做得很好Martin!我可以确认,这个也可以。你需要将这个添加到你的模型中吗?我想我会用整洁的方式。。。通常情况下,您只需要在自定义sql查询中选择字段的子集。这应该是可能的,而无需将其添加到您的模型中。。。
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        ...
    
        modelBuilder.Entity<MyCustomModel>().HasNoKey();
    }
    
    async public Task<List<MyCustomModel>> GetMyCustomData()
    {
        var rv = new List<MyCustomModel>();
        using (var dataContext = new DbContext())
        {
            var sql = @"
                select textField as 'Text', count(1) as 'Count'
                from MyTable";
            rv = await dataContext.Set<MyCustomModel>().FromSqlRaw(sql).ToListAsync();
        }
        return rv;
    }