Note: The feature tracked in this issue could help with using EF Core with database views. However, the feature is not limited to database views and its completion would not mean that every aspect of database view support has been implemented. See #827 for an overview of the areas where EF Core interacts with database views.
We want to enable modeling types that exist independently of entities but have no keys (and therefore are not updatable) as first class objects in EF Core models.
FromSql()
or defining query, having result types that don't need to have keys makes the feature much more useful.We can consider renaming the feature to something else if we find a better name. So far the list is short:
Table valued functions can return an arbitrary type. Usually this result is then cross applied with other parts of the query, but it can just be selected. I need a way to map this type and I think this feature could help with that.
@pmiddleton that is exactly right. I will add it to the list or related features.
In this context, you should also support temporary tables.
The lack of views support is still a show stopper for me as my solutions heavily depend on them.
Please also consider that SQL Server views can be updatable.
No matter how views support is (going to be) implemented please at least make sure that code can be quickly fixed to allow for updates. Eg. adding PK (HasKey/[Key]) is sufficient to allow for basic updates
@tdjastrzebski Can you elaborate on what isn't working for you? You can already map entity types to database views and it will work fine (provided the views are updatable) - We make no distinction between views and tables when generating SQL during query or update.
This feature is not really about database views, but about being able to model key-less structural types.
@anpete I assumed views were not supported at all since entity classes were not generated - at least not using Scaffold-DbContext. Maybe there should be a switch added?
I registered new issue #9854, duplicate of #1679
Tables/Views distinction makes no sense. Drop this concept please.
Even in SQL Server tables can be read-only while views can be updatable.
EF Framework was going to be universal entity framework, not just DB entity framework.
In my view here EF Framework Team goes wrong direction.
My proposition: scaffold entities for all SQL tables and views. Those with no PK will remain read-only.
See #9854 for what currently I need to do to accomplish exactly what I need.
I understand the concern may be error-proneness and product quality perceived by the beginners but versatility, simplicity and functionality shall prevail.
RE: Those with no PK will remain read-only
@tdjastrzebski, however, there can be read-only views and stored procedures that "do" return data with PKs; IMHO using the PK to derive (read-only/write access) may not be the best option; perhaps this would work for you #1862
@Vasimovic correct, this may not be 100% reliable option. Similarly, scaffolding will perhaps never be 100% correct with that respect simply because new providers will be implemented with functionality we cannot even predict yet. So why bother with special view classes? Just so the developer does not get exception when he/she tries what is not supported?
If so, ReadOnlyDbSet
It just seems freaky to be lacking support for such a fundamental thing this far down the line.
We gave up, and we use LLBLGen Pro, as that supports Views in its .NET Core 2 Runtime Framework.
https://www.llblgen.com/
Now we have automatic context, high performance, and even automatic generation of DTO objects from a database-first perspective when we want it (and yes, we have diagrams to understand entity relationships)
It might not be the most user friendly system to use (that's an understatement) but it's incredibly powerful, fast, and reliable. Oh, and did I mention it supports views in .Net core?
I vote for this feature. I am using EF Core 2.0 to load results from a view I'm using as part of a complex search. The view does not have a primary key.
In order to satisfy Entity Frameworks primary key requirement I lied and told EF that a column is a primary key. EF produced the result-set and all looked OK at first, but I found that when the "key" column contained duplicates - EF had replaced all subsequent rows with an exact copy of the first row for each "key" value!!! There was no warning, no error! OK, I did lie about the key, so I suppose EF has the right to lie back to me.
My eventual workaround for this was to manufacture an ID column using ROW_NUMBER() and use that column as the key. So, Entity Framework seems needy requiring this key definition.
I vote to have a View Type (or possibly call it a Report type or a Read-Only type). This entity type would not care about keys or change tracking, so it could be simple and light-weight.
@renbud Then how updatable views should be treated?
I suggest treating them exactly the same way as tables after when PK is specified and that usually has to be done 'manually'. In consequence there are two types of DB views which have to be handled differently.
@tdjastrzebski ReadOnlyDbSet as you suggested seems the way to go.
It may not be just for views. Could also be for stored procedures, or ad-hoc queries.
There can be many use-cases for read-only access.
@renbud I meant more how to reasonably decide during reverse engineering which DbSet should be ReadOnly since it may not be straight forward.
@tdjastrzebski I thought either
a) The lack of a Key property would cause the DbSet to behave as ReadOnly
or
b) A new explicit ReadOnly property on DbSet
or
c) The developer explicitly asks for a ReadOnlyDbSet e.g.
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
...
public ReadOnlyDbSet<MySearchResultView> SearchResults { get; set; }
...
}
}
I think any of these would work for me, although possibly (c) seems the cleanest.
@renbud yes (c) or (b) would be better not to mention that having a read-only DB set would be useful.
However, that does not solve the primary key issue which may or may not exist in the model and the fact that you have to add (view/read-only) models to the DbSet
I think this would be better #1862; Mapping Arbitrary Types. The primary key is optional or treated as a regular column, and there is no need to add models to the DbSet's (there could be thousands of read-only models, adding them to a DbSet would add unnecessary overhead)
@Vasimovic I agree #1862 captures my use case. If ad-hoc sql could be mapped to an arbitrary type in a read-only manner then I would be happy. Essentially I am just looking for an easy way to capture reports output into a Dot Net collection.
@Vasimovic While I am typically looking for updatable views to be handled exactly like tables.
@tdjastrzebski I understand, there are two issues here, updatable views (should be bound to DbSet) and mapping of arbitrary types (not bound to DbSet)
It's good to see some work done on this. Would also be great if the documentation explaining how to use query types is provided somewhere!
@tdjastrzebski Again, EF Core does not care whether you are mapping entity types to database tables or updatable views. Scaffolding does not support views, but you can easily hand write entity types and map them perfectly well to views (via ToTable) - Yes, ToTable is somewhat confusing here, but the way to think about this is that it is simply allows you to configure the name of the database _object_ that EF will use when generating SQL.
Additionally, in 2.1 we are adding Query Types, which allow you to define model types that do not have identity. These can also be mapped to tables or views in the database but are never tracked and are therefore essentially read-only.
@alexzaytsev-newsroomly Expect docs to accompany the release. For now, you can take a look at our tests:
https://github.com/aspnet/EntityFrameworkCore/blob/dev/src/EFCore.Specification.Tests/TestModels/Northwind/NorthwindContext.cs
https://github.com/aspnet/EntityFrameworkCore/blob/dev/src/EFCore.Relational.Specification.Tests/TestModels/Northwind/NorthwindRelationalContext.cs
https://github.com/aspnet/EntityFrameworkCore/blob/dev/src/EFCore.Specification.Tests/Query/SimpleQueryTestBase.QueryTypes.cs
Created #10753 to track the remaining work here.
@anpete Will we still need to define a DbQuery with Stored Procedures?
I was hoping for something like FromSql (FromQuery) without the DbSet to map to POCO classes
@Vasimovic No, you don't need a DbQuery property on your context (if that's what you mean). You _do_ need to register the query type in OnModelCreating, via modelBuilder.Query<T>()
- This is what #10753 is about, i.e. allowing the query type to be added to the model lazily, but it is really only a small piece of the puzzle. Of course, the ModelBuilder configuration is often required anyway because it is where you perform any other mapping configuration for the query type. E.g. calling ToTable, ToColumn etc. In this way, Query Types are better than what we had in EF6 because they have more mapping capabilities, such as inheritance and outbound nav props.
You can use FromSql in the same way as with entity types. E.g. context.Query<OrderView>().FromSql("...")
.
@anpete Just so I get this right: So modelBuilder.Query<T>
is basically the same thing as modelBuilder.Entity<T>
except that the configured type does not have the restrictions entities have (e.g. having a table and identity)? That鈥檚 great! :)
The 2.1.0 does not seem to be available from the nuget.org prerelease source feed within Visual Studio 2017. Do I have to build from source if I want to try QueryType now?
@samuelan Prerelease builds are only available on myget, as described here. So you should probably try the version from the aspnetcore-dev feed
Thanks, @poke . Will try it out.
@anpete I don't see how this will work without having a baseline DBSet object that allows primary key. For me, this requirement should mean I can query a view as read only and not require a DBSet object to do so. I am unable to do that in the 2.1 version. I am working with existing database views and I am thinking I just don't understand the full functionality here. Any ideas?
@emmielewis Are you using the nightly builds? What is not working exactly?
@anpete - I am using build 2.1.0-preview2-t000. I looked at your example and set it up in a similar fashion but your example is using a DBSet object to build a query. It works when I do that. In my case, I have an existing view that I want to represent as an object and don't want to use the DBSet object (avoid primary key requirement) in order to create a query. How do I use DBQuery with an existing database view without any primary key requirements at all? Do I have to use a DBSet object to build this in EF?
@emmielewis You have hit a quirk of our APIs here 馃槃 You map a Query Type to a view by using ToTable
. E.g. modelBuilder.Query<AT_DetailView>().ToTable("ccc.dddddd");
@anpete - Ok. I think I got confused from the example. I just saw your note above that says "ToTable" is a bit confusing. I am trying this out now.
@anpete - Thank you! That works great for me!
@emmielewis Hard to say. Is there a lot of data? It uses the same code paths as regular entity queries and so perf. should be the same.
@anpete - I got it resolved. This is working great. Thank you!
modelBuilder.Query
@emmielewis - QueryType.ToTable API has been renamed to QueryType.ToView in 2.1.0-preview2
Yep. I just noticed that. Can you all update your documentation with this information? https://docs.microsoft.com/en-us/ef/core/modeling/query-types
cc: @divega
@smitpatel, @emmielewis I created https://github.com/aspnet/EntityFramework.Docs/pull/682/.
I have had similar problems. I want to return a model or type that is not in the DBContext. So, I return it as Json from SQL 2016:
Add a table to the database with a key (int or guid) and a string value
public class JsonReturn
{
public int Key {get;set;}
public string Return {get; set;}
}
I then use that model with a FromSql statement
var dbReturn = _db.JsonReturn.FromSql($"dbo.Csp_StoredProc {param1}, {param2}").FirstorDefault();
then I parse the Json out into the ViewModel or DIO that I need.
List<T> lp = JsonConvert.DeserializeObject<List<T>>(json);
This would work with views as well would it not? Even an update statement.
Am I just looking at this to simply?
Most helpful comment
I vote for this feature. I am using EF Core 2.0 to load results from a view I'm using as part of a complex search. The view does not have a primary key.
In order to satisfy Entity Frameworks primary key requirement I lied and told EF that a column is a primary key. EF produced the result-set and all looked OK at first, but I found that when the "key" column contained duplicates - EF had replaced all subsequent rows with an exact copy of the first row for each "key" value!!! There was no warning, no error! OK, I did lie about the key, so I suppose EF has the right to lie back to me.
My eventual workaround for this was to manufacture an ID column using ROW_NUMBER() and use that column as the key. So, Entity Framework seems needy requiring this key definition.
I vote to have a View Type (or possibly call it a Report type or a Read-Only type). This entity type would not care about keys or change tracking, so it could be simple and light-weight.