I am using EF 6 to connect to an existing SQL database. I want to generate a model for some existing entities and non-CRUD stored procedures. From visual studio, I am adding a new "ADO.NET Entity Data Model" and selecting "Code First from Database" for the model content. However, the only database objects that are available to me are Tables and Views. Stored procedures aren't available. Is this by design or am i missing something here?
You need to define a DTO for each stored procedure. You just create simple classes where the propery names of the classes match the name of the columns that are returned by the stored procedure. So, when you call the Stored Procedure from EF, your objects are built and populated. The performance is great!
Here I'm pasting an example:
dbContext.Database.CommandTimeout = 3600;
List<CarsDTO> objs = dbContext.Database.SqlQuery<CarsDTO>(
"spGetCars #carMakeId", new SqlParameter("carMakeId", id)
).ToList();
Related
I am working on an asp.net mvc application using C#. For database, I am using Entity Framework and code-first approach. I have an sql view that I need to execute and store its result in a list. I know how to query data from DB using ApplicationDbContext, stored procedure and inline queries. But now I want to do the same using a view.
The view looks like this
CREATE VIEW [dbo].[GenresView]
AS SELECT * FROM Genres
I have a Genre class that has the same properties that the view will return.
Steps to handle a view:
Create a GenresView class with properties mapped to view columns. You can use EF features like virtual properties and ForeignKey annotations to be able to load entities related to the view in your queries.
Add the created entity as a new property DbSet GenresView to your database context.
Add new migration using Package Manager Console and add migration command.
As you can notice, the generated migration contains statements for creating a new table for the GenresView in the Up() method. Delete this code and replace it with Sql(#"CREATE VIEW dbo.GenresView AS SELECT * FROM Genres") statement.
IMPORTANT!!! It is better to define all fields which you want to get instead of * .
You should also replace the code in the Down() method to be able to revert the migrations properly. Its code should contain call to Sql(#"DROP VIEW dbo.GenresView").
Update the database.
Now you can use the new entity in your LINQ statements as it were a regular table (e.g. dbContext.GenresView.).
I came across this related question: How can I generate DDL scripts from Entity Framework 4.3 Code-First Model?
But this doesn't appear to answer the question of when a Code First application actually checks the existence/correctness of the DB and modifies it if necessary. Is it at run-time or build time? Assuming it's at run-time is it at start-up or when you create the DbContext or at the last possible moment e.g. when you try to write/read the DB table(s) it checks they exist on a case-by-case basis?
It is ceated at rutime the first time you access an entity, ie,
using (var db = new MyDBContext())
{
var items = db.MyObj.Count() // <- Here it is created!
}
There are some flavors on how, like if you set the creating strategy to CreateDatabaseIfNotExists, DropCreateDatabaseAlways, Etc. Please give this a look:
http://www.entityframeworktutorial.net/code-first/database-initialization-strategy-in-code-first.aspx
The column Model in the table __MigrationHistory is serialized and gzipped(base64) version of your EDMX. In code first the column Model is generated by Add-Migration and stored in the second part of the migration partial class and in the database when the database is created as binary stream varbinary(max).
When the database initializer (Database.SetInitializer) is called, then EF generate from the classes on the fly(Runtime) the current Entity Data Model(EDMX). The generated model will be serialized, zipped(base64) and finally compare it with the stored Model of the migration history table.
The comparison happens before the DbContext is created and, if the two Models(binary streams) are not identical then you will get a compatibility exception.
I am using EF reverse POCO generator. When I save the .tt file it automatically generates the return model of all the stored procedures.
In couple of my SP's, I have a user defined table type as one of the input params. For those SP's, my POCO is not creating the return models.
Earlier I had this issue for normal SP for which I used a return query from the temp tables. Adding SET FMTONLY OFF on top of the SP fixed that.
I am pretty sure it is with using the user defined table types that is causing the issue because when I just remove them, the return models are generated.
I am looking for a fix to this. Any help would be greatly appreciated.
I currently use a database-first approach using Entity Framework (EF). I'm investigating different ways of calling stored procedures (stored procedures that are NOT tied to entities) using EF. Currently, I'm using the approach found here using the designer (in this approach, I import a stored procedure, create a function import and use a complex type as my mapped object). I don't like this because it relies on a bloated EDMX file and it causes merge conflicts in source control when two or more people perform this procedure and check in their code.
I found this post which claims I can call a stored procedure and map to a plain old C# object (POCO).
My question is if I want to map to a POCO to a stored procedure in EF not using the designer approach, how do I get aliases for column names? For example, let's say I call a stored procedure and get a particular column back named "CustomerID" and I want the property mapped to it to be named "Id" instead of "CustomerID". How can I do this without using the designer approach?
Something like the following should work:
[your db context].Database.SqlQuery<[your POCO class]>("[name of stored proc] [comma separated parameters]", parameter1, parameter2, .....)
Here's example from one of my applications:
_context.Database.SqlQuery<Library>("usp_paged_select_libraries #userId, #offset, #fetch", userIdParameter, offsetParameter, fetchParameter);
Within your POCO you would mark up your properties with:
[Column("[your alias here]")]
I am trying to get to grips with the Entity framework, and have a requirement to order results by distance from a point on the globe. I have decided on previous advice to do this using a stored procedure which I have successfully done populating a view. However I need to return multiple tables, which I understand I cannot do directly using stored Procedures on the Entity Framework. If this is not correct, I would be grateful if someone could advise how I might do this.
Anyway I therefore have defined a simple sp (SELECT id FROM table) and then wanted to perform a linq query to join this with the equivalent object in my model as follows:
var sp = db.StoredProcedure();
var ret = from x in db.X
join y in sp on x.ID equals y.ID
select x;
However when I perform this I get the following exception resulting from the query:
"Unable to create a constant value of type 'System.Collections.Generic.IEnumerable'1'.Only primitive types('suchas Int32, String, Guid') are supported in this context."
Why is this happening? Is this the right approach? (Note that my final sp will be more complex, and I will be returning multiple classes from the select in 'ret')
Use EF Extensions
Stored procedures are really badly supported in EF. Even if they return entity results, they don't provide any name mappings, so you have to rename columns in stored procedures yourself.
But. There's project called Entity Framework Extensions that will make all kinds of different scenarios with stored procedures possible.
Using EF extensions you can use stored procedures in any way you want:
you can do column remappings in your custom materializer (so your stored procedure returns same columns as they are in the DB without the need to rename columns to entity property names)
you can return multiple result sets (great for 1:* and : relations)
you can use scalar stored procedures or even procedures that don't return anything
you can consume results from a stored procedure that returns multiple entities per row (when having 1:1 relation between two of them)
you can also use output parameters which is great if you create a stored procedure that does paging (returns a subset of records as entities and returns out parameters with total count)
etc.
You can do preety much anything. We've used EF Extensions with much success on a some project. We wrote our own materializers (basically a lamba expression) for entities that our stored procedures returned. And then we materialized their results.
I don't think EF4 will support stored procedures to this level anyway, so getting acquainted to EF Extensions is always valuable.
The EF in .NET 3.5 SP1 cannot map procs which return scalar values (in .NET 4.0 you can). The SP must return all the values necessary to materialize a full entity, which is likely more than just the ID.
Also, it's almost never correct to use the "join" reserved word in LINQ to Entities. You traverse relationships in your client schema instead.
Start by writing a proc which returns all values necessary for an entity type. Map that proc. Then do:
IQueryable<MyEntity> q = from e in Context.MyEntities
select e;
Then move on from there.