My model is using a database-first approach where stored procedures are not imported and exist only in the database.
I need to execute my stored procedures via ExecuteSqlCommand and I would like to track those changes, but unfortunately entities modified by executing stored procedures (insert, delete) are not listed in ChangeTracker().Entries.
I've tried:
context.Database.BeginTransaction();
var result = context.Database.ExecuteSqlCommand(storedProcedureName, parameters);
var trackedEntities = context.ChangeTracker
.Entries()
.Where(x => x.State != EntityState.Unchanged)
.ToList();
context.Database.CurrentTransaction.Commit();
I've also tried to dig in current transaction but actually there is nothing that I could use. Next idea was to force my Entity to get in change tracker with state unmodified with querying it via linq and than run stored procedure but it seems it's not tracked ad all.
I'm out of ideas. This is required to rollback changes done by stored procedures after test finish.
Try Database.SqlQuery<TElement>(String, Object[]):
Creates a raw SQL query that will return elements of the given generic type. The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
Or DbSet<TEntity>.SqlQuery(String, Object[]):
Creates a raw SQL query that will return entities in this set. By default, the entities returned are tracked by the context;
Related
I am new to Entity Framework and Linq, I would like to understand how dbset/dbcontext works when executing the following kind of LINQ request:
from x in db.Products select x
db is the data context object, Products the dataset.
Is the search/loading of these records done directly at the base table level or is a first search done on the dbset? And then we complete and retrieve the records that are not yet tracked/in the dbset?
In other words what is the path of the loading of these elements?
Thank you,
Is the search/loading of these records done directly at the base table level or is a first search done on the dbset?
It's done so at the "base table level" in the Database Server by receiving the results directly from the query and then DataContext will return any existing entity that it already have track of and create new entities if it doesn't have any track for those records.
And then we complete and retrieve the records that are not yet tracked/in the dbset?
The DataContext will create new entities for those records and it'll be tracked if you didn't explicitly specify AsNoTracking.
In other words what is the path of the loading of these elements?
The way it works from this document is that when you make a LINQ Query like this:
from x in db.Products select x
It will generates a LINQ Expression and then pass that expression to the Database Provider to generate the actual database query specific to the database engine it's made for (it may not have all of the query compiled, so some of the query may be computed from the application side.)
It will then execute the query and receive the result from that query and if the query is made with tracking, then it'll return any existing entity that the DataContext already have track of and create new entities if not.
The entity and record will be tied by the key and whenever there is any part of the query using Keyless Entity Type, the whole query would be made as a NoTracking query.
Note that if the database record for such existing entity have changed, it will not update the values in the existing entity, you will have to manually reload that entity like so:
db.Entry(product).ReloadAsync();
I'm developing a database application using Entity Framework 6. In one place, I need to assemble a query based on user input and then return that query to the caller. I can't run the query myself and return the result set because the caller needs to store the query to run again later if the UI is refreshed. I also can't return an IQueryable representing the assembled query because this is only valid for the context against which it was assembled.
I've looked at using CompiledQuery.Compile but this doesn't work with the DbContext base class in Entity Framework 6. I need to do something like that, pre-compiling/pre-assembling/pre-constructing a query that can be returned and run again later, but that works with Entity Framework 6. I don't care whether the query is returned in the form of a delegate or whatever, I just need something that represents the query independently of any specific context instance.
How can I pre-construct and return a query with Entity Framework 6 such that it can be run multiple times against different context instances?
What I ended up doing was creating a delegate type to encapsulate the queries, that takes MyDatabaseContext as a parameter and returns a List<T> where T is the type of the particular entity that I'm querying for.
So now the function that creates the query can simply return a function and whenever the query needs to be run the query is simply called as a function passing it the context instance to act upon as a parameter. The function returns from the given context a list of entities as applicable for the query that it represents.
I create a stored procedure which returns a table (physically stored table).
CREATE PROCEDURE uspTest
AS
BEGIN
SELECT * from Table1
END
When I capture the output using Entity Framework, it loads up the entity properly.
var output = entities.Database.SqlQuery<Table1>("dbo.uspTest").ToList<Table1>();
the "output" variable contains the data returned from SP but it this List of Table1 object doesn't not load up foreign key tables automatically. I added below code to mitigate this problem
foreach (var member in output)
{
entities.Table1s.Attach(member);
}
After attaching each entity all child tables are linked for each Table1 member. But, when I come back to this same method second time, it gives me an error failing to attach.
Attaching an entity of type 'Table1' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values.
i tried setting the state of entity to detached but of no luck!! Does anyone have any clue what i should do here?
I'm using Database first approach.
The results of Database.SqlQuery<TElement> are never tracked by the context even if the type of object returned is an entity type. If you want the returned entities are tracked by the context, then you should use DbSet<TEntity>.SqlQuery method:
var output = entities.Table1s.SqlQuery("dbo.uspTest").ToList();
This way you don't need to use extra code to attach the entities.
But, why do you want to access to the Table1 using a SP when you already have the DBSet<Table1> Table1s?. I guess you have a more complex stored procedure and you did this to explain your issue, but if that is your SP, as #DLeh commented above, you should use Linq to Entities.
When working with stored procedures in linq, I can go to my SP and select what type of entity it should be returning. This works fine in most cases, except the time's I'm not sure of what will be returned. If I don't select what type of entity to return i get the standard
return ISingleResult<SP-Name>
I thought I would be able to work with this return type like this:
List<SP-Name> myResult = context.SP-Name("London");
But this gives me an error offcourse, about implicit converting ISingleResult to List.
How should I do to be able to work with this <SP-Name> returntype?
If you don't specify an entity in your Linq-to-SQL model to be used as the return type for your stored procedure, then Linq-to-SQL autogenerates a type for you.
This is a straight .NET class, so you can inspect its properties and so on - but since it's not one of the entities in you database model, obviously, you cannot save it back to the database and there's no set of that type on your db context, either.
As I said - you can inspect the properties of the return type, you can use that to update other "proper" entities of your Linq-to-SQL model and then save those.
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.