Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query Types: Model types that do not require identity #9290

Closed
Tracked by #827
divega opened this issue Jul 28, 2017 · 43 comments
Closed
Tracked by #827

Query Types: Model types that do not require identity #9290

divega opened this issue Jul 28, 2017 · 43 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@divega
Copy link
Contributor

divega commented Jul 28, 2017

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.

Relationship between query types and other features:

  • We consider this a stepping stone to enable ad-hoc mapping for arbitrary types (Support for querying objects without keys #1862)
  • The plan may involve enabling "defining queries", originally described in Support for defining query in query types #3932 for these types, because query types are not necessarily mapped directly to database tables or views.
  • We could also have the ability to introduce a "null" defining query for query types that will only be used in ad-hoc queries. Note that defining queries (including null defining queries) could later be enabled for entity types, but we need a way to map CUD operations.
  • One thing query types can help with is as the result type for Table-Valued Functions (covered by Query: Additional function mapping capabilities #4319). If we enable some kind of first class mapping of TVFs or even for TVFs using in FromSql() or defining query, having result types that don't need to have keys makes the feature much more useful.
  • Query types are related to owned types conceptually. You could think about them as owned types that don't happen to have an owner 😄 (hence no identity, hence no ability to update)
  • Query types are different but somewhat related to the idea of supporting database views. In the past when this has been brought up it was usually about mapping database views to entity types (e.g. Improved view support #827, RevEng: Support Views #1679) but if we have query types in the model then one could choose to map them to views in the database, and that would also be more flexible because database views don't necessary have keys and are not necessarily updatable.
  • It could also be related to supporting the definition of views and the creation of views in migrations described at Create database views in Migrations using SQL generated from a LINQ projection #465.

Alternative names for the feature

We can consider renaming the feature to something else if we find a better name. So far the list is short:

  • View types
  • Structural types
@divega divega added this to the Backlog milestone Jul 28, 2017
@pmiddleton
Copy link
Contributor

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.

@divega
Copy link
Contributor Author

divega commented Jul 28, 2017

@pmiddleton that is exactly right. I will add it to the list or related features.

@MarcoLoetscher
Copy link

In this context, you should also support temporary tables.

@tdjastrzebski
Copy link

tdjastrzebski commented Sep 16, 2017

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

@anpete
Copy link
Contributor

anpete commented Sep 16, 2017

@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.

@tdjastrzebski
Copy link

tdjastrzebski commented Sep 17, 2017

@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?

@tdjastrzebski
Copy link

tdjastrzebski commented Sep 19, 2017

I registered new issue #9854, duplicate of #1679

@tdjastrzebski
Copy link

tdjastrzebski commented Sep 23, 2017

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.

@Vasim-DigitalNexus
Copy link

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

@tdjastrzebski
Copy link

tdjastrzebski commented Sep 23, 2017

@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 is another option which I think might be viable. Those who know what they are doing can change ReadOnlyDbSet to DbSet derived from ReadOnlyDbSet and voilà.

@jsobell
Copy link

jsobell commented Oct 24, 2017

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?

@renbud
Copy link

renbud commented Dec 18, 2017

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.

@tdjastrzebski
Copy link

@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.

@anpete
Copy link
Contributor

anpete commented Jan 23, 2018

@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

@anpete
Copy link
Contributor

anpete commented Jan 23, 2018

Created #10753 to track the remaining work here.

@anpete anpete closed this as completed Jan 23, 2018
@Vasim-DigitalNexus
Copy link

@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

@anpete
Copy link
Contributor

anpete commented Jan 24, 2018

@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("...").

@poke
Copy link

poke commented Jan 24, 2018

@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’s great! :)

@ajcvickers ajcvickers modified the milestones: 2.1.0, 2.1.0-preview1 Jan 24, 2018
@samuelan
Copy link

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?

@poke
Copy link

poke commented Feb 14, 2018

@samuelan Prerelease builds are only available on myget, as described here. So you should probably try the version from the aspnetcore-dev feed

@samuelan
Copy link

Thanks, @poke . Will try it out.

@emmielewis
Copy link

emmielewis commented Feb 26, 2018

@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?

@anpete
Copy link
Contributor

anpete commented Feb 26, 2018

@emmielewis Are you using the nightly builds? What is not working exactly?

@emmielewis
Copy link

emmielewis commented Feb 26, 2018

@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?

image

@anpete
Copy link
Contributor

anpete commented Feb 26, 2018

@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");

@emmielewis
Copy link

@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.

@emmielewis
Copy link

@anpete - Thank you! That works great for me!

@anpete
Copy link
Contributor

anpete commented Feb 26, 2018

@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.

@emmielewis
Copy link

@anpete - I got it resolved. This is working great. Thank you!

@emmielewis
Copy link

emmielewis commented Apr 16, 2018

modelBuilder.Query().ToTable("TestView", "TestSchema") is not working in the https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/2.1.0-preview2-final in Nuget. It looks like you all changed the name to ToView. Can you all update your documentation with this information?

@smitpatel
Copy link
Contributor

@emmielewis - QueryType.ToTable API has been renamed to QueryType.ToView in 2.1.0-preview2

@emmielewis
Copy link

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

@smitpatel
Copy link
Contributor

cc: @divega

@divega
Copy link
Contributor Author

divega commented Apr 17, 2018

@smitpatel, @emmielewis I created dotnet/EntityFramework.Docs#682.

@r10-dev
Copy link

r10-dev commented May 1, 2018

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
Development

No branches or pull requests