Using Entity Framework 6, I was able to use execute a Raw SQL Query and use a custom model which was not defined in the DBContext in order to store the output of the query. A simple example is the following:
List<MyModel> data = context.Database.SqlQuery<MyModel>("SELECT Orders.OrderID, Customers.CustomerName FROM Orders INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;").ToList();I execute one SQL command and I expect a list of custom models.
I try to do something similar with Entity Framework Core and the closest example that I found will force me to define a property from DBContext. This will not allow me to use a custom model to fill the data that SQL server will return.
var books = context.Books.FromSql("SELECT * FROM Books").ToList();This query informs Entity Framework Core that the query will return a list of books. Is there a way to implement something like this in Entity Framework Core?
- 2Not yet. Eventually will be possible in some future EFC release. SeeRaw store access APIs: Support for ad hoc mapping of arbitrary types #1862 andView types support #9290.Ivan Stoev– Ivan Stoev2018-01-16 10:16:17 +00:00CommentedJan 16, 2018 at 10:16
- Thank you for your reply. So I have to wait for this future.pitaridis– pitaridis2018-01-16 10:48:14 +00:00CommentedJan 16, 2018 at 10:48
- More on this feature here:msdn.microsoft.com/en-us/magazine/mt847184.aspxGert Arnold– Gert Arnold2018-07-11 21:03:14 +00:00CommentedJul 11, 2018 at 21:03
4 Answers4
From .NET Core 2.1:
Add
modelBuilder.Query<YourModel>()toOnModelCreating(ModelBuilder modelBuilder)Use
context.Query<YourModel>().FromSql(rawSql)to get data
5 Comments
YourModel? I have a custom class with productname and quantity. Used the same technique like in the asked question which worked in EF5.x. I have EF core in a .Net standard 2.0 class lib. :-SmodelBuilder.Entity<YourModel>().HasNoKey().Here's how I was able to get this working (for completeness):
MyModel.cs:
public class MyModel{ // The columns your SQL will return public double? A { get; set; } public double? B { get; set; }}Add class that just inherits from your original EF context class (i called mine 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(); }); }}Use that class (instead of your original EF context class):
// Use your new db subclassusing (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"}Notes:
- If you need to, just use
FromSqlInterpolatedinstead ofFromSqlRaw - The "db context" subclass allows you to update EF models without affecting your "polyfill" code
- Works with SQL Server stored procs that return only 1 result set
2 Comments
The question was about .NET Core 2. Now I have a solution and I am going to write it here so that someone else could use it in case he/she needs it.
First of all we add the following method in dbContext class
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; }}Now we can have the following code.
List<Customer> Customers = _context.ExecSQL<Customer>("SELECT ......");4 Comments
follow these steps:
Create your model
Probably it could be better if you can reduce it to a model as generic as possible but it's not a must:
public class MyCustomModel{ public string Text { get; set; } public int Count { get; set; }}Add it to your own DbContext
CreateDbSet for your custom model
public virtual DbSet<MyCustomModel> MyCustomModelName { get; set; }Keep in mind to specify your custom model has no key
protected override void OnModelCreating(ModelBuilder modelBuilder){ base.OnModelCreating(modelBuilder); ... modelBuilder.Entity<MyCustomModel>().HasNoKey();}Use it from your dbContext instance
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;}1 Comment
Explore related questions
See similar questions with these tags.





