具有自定义模型的实体框架Core Raw SQLQueries

时间:2018-01-16 09:44:24

标签: asp.net-core entity-framework-core asp.net-core-2.0

使用Entity Framework 6,我能够使用执行原始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();

我执行一个SQL命令,我希望有一个自定义模型列表。

我尝试用Entity Framework Core做类似的事情,我发现的最接近的例子将迫使我从DBContext定义一个属性。这将不允许我使用自定义模型来填充SQL服务器将返回的数据。

var books = context.Books.FromSql("SELECT * FROM Books").ToList();

此查询通知Entity Framework Core查询将返回书籍列表。有没有办法在Entity Framework Core中实现这样的东西?

4 个答案:

答案 0 :(得分:6)

从.NET Core 2.1:

  1. modelBuilder.Query<YourModel>()添加到OnModelCreating(ModelBuilder modelBuilder)

  2. 使用context.Query<YourModel>().FromSql(rawSql)获取数据

答案 1 :(得分:2)

这是我如何能够正常工作的原因:

MyModel.cs:

public class MyModel
{
    // The columns your SQL will return
    public double? A { get; set; }
    public double? B { get; set; }
}

添加仅从您的原始EF上下文类继承的类(我称为我的DbContextBase):

public class DbContext : DbContextBase
{
    public virtual DbSet<MyModel> MyModels { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // Necessary, since our model isnt a EF model
        modelBuilder.Entity<MyModel>(entity =>
        {
            entity.HasNoKey();
        });
    }
}

使用该类(而不是原始的EF上下文类):

// Use your new db subclass
using (var db = new DbContext())
{
    var models = await db.MyModels.FromSqlRaw(...).ToListAsync();    // E.g.: "SELECT * FROM apple A JOIN banana B ON A.col = B.col"
}

注意:

  • 如果需要,只需使用FromSqlInterpolated而不是 FromSqlRaw
  • “数据库上下文”子类允许您更新EF模型,而不会影响“ polyfill”代码
  • 与仅返回1个结果集的SQL Server存储过程配合使用

答案 2 :(得分:1)

请按照以下步骤操作:

创建模型

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

public class MyCustomModel
{
   public string Text { get; set; }
   public int Count { get; set; }
}

将其添加到您自己的DbContext中

为您的自定义模型创建DbSet

public virtual DbSet<MyCustomModel> MyCustomModelName { get; set; }

请记住,指定您的自定义模型没有密钥

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    ...

    modelBuilder.Entity<MyCustomModel>().HasNoKey();
}

从您的dbContext实例中使​​用它

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

答案 3 :(得分:-1)

问题是关于.NET Core2。现在我有一个解决方案,我将在这里编写它,以便其他人可以在需要时使用它。

首先,我们在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;
    }
}

现在我们可以有以下代码。

List<Customer> Customers = _context.ExecSQL<Customer>("SELECT ......");