-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Support passing DbParameter instances to raw SQL APIs #3115
Comments
Note for triage: We should support passing in DbParameters as well as just the raw values (we supported this in EF6), but it doesn't work at the moment. |
Dictionaries are cool and all but the 'micro-orm' approach of allowing anonymous objects to be passed in is much more convenient. |
I also vote for anonymous object approach to pass in the named parameters. |
Hi, is were a way to get FromSql working if I don't have Id or identity column ? |
Using ExecuteSQLCommand Whats the best way of getting the value of an SqlParameter of type System.Data.ParameterDirection.Output as it stands. Do I need to go back to SqlCommand |
@mikes-gh - yes, for the moment. |
How do we return an output value ? For example I have a stored procedure that returns 0 if everything goes well and 1 if an error occurs . Based on @mikes-gh I think SqlCommand is the only way out for now or ? |
@tessSnap Yes, dropping down to ADO.NET is going to be the solution until we remove this limitation. |
For those of you using SQL command I found this useful to get a connection string from existing context. someContext.Database.GetDbConnection().ConnectionString then use a new connection . I tried to borrow context connection and cast to SQLConnection for my command but doing that breaks the context you borrowed from. |
This code is working for me. I am using Connection object.
|
Yes that works. But subtly if you try to use the context afterwards it is broken. Hence my message. |
Have you enabled Multiple Active Result Sets (MARS). In my code, I was using the context after my SP and it is working (without enabling MARS). You need to close the connection after your initial query.
|
I had to resort to SQLCommand. In EF6 I use to enjoy dbCtx.Database.SqlQuery("select... blah from... |
@jvelezc - you can still do the dynamic sql query as shown below var actual = await context.Set<Customer>()
.FromSql(@"SELECT * FROM ""Customers"" WHERE ""ContactName"" LIKE '%z%'") |
My problem is that Customer has to be DbSet (an entity). In the past I was able to create a viewmodel that was not part of DbSet on dbcontext class and return it. |
Entity Framework needs to create an object for you, hence you need to define your ViewModel as DbSet (there is no requirement of having a table with the same name in the database). If you are looking for a dynamic object, please vote for this enhancement #2344 |
So... If I do where announcement is an entity
Everything works as expected. However! If I do a ViewModel and for simplicity sake I will make it exactly equal to announcement just to show that the only difference is the type.
and then Then
Creates an exception Value cannot be null.Parameter name: entityType If I then remove builder.Ignore(); and re tun the test after having updated to the latest model changes and adding a [key] attribute to annoucement viewmodel then it works. However, it created a table in my database. So ... how do you do it so that you can use viewmodels FromSQl('') and not have to register in the database. |
Are you using EnsureCreated() to create tables from code. If yes, then you need to use builder.Ignore(). Otherwise you don't need to use Ignore. You still need to declare a Key for your ViewModel, but you don't need the Table attribute. I am using FromSql to execute a stored procedure and here is my code for this //defining the entity class
public class ProductSummaryEntity
{
[Key]
public long RowId { get; set; }
public int ProductTypeId { get; set; }
public string ProductTypeName { get; set; }
public int QuarryId { get; set; }
public string QuarryName { get; set; }
public int MaterialCount { get; set; }
} My DbContext public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>
{
// rest of DbSet objects
public DbSet<ProductSummaryEntity> ProductSummary { get; set; }
} //calling the stored proc
return await dbContext.Set<ProductSummaryEntity>().FromSql("dbo.ProductSummaryGet @CompanyId = {0}, @QuarryIds = {1}, @ProductTypeIds = {2}, @StartDate = {3}, @EndDate = {4}"
, profile.CompanyId, quarryIds, productTypeIds, search.StartDate, search.EndDate
).Select(m => Mapper.Map<ProductSummaryEntity, ProductSummaryModel>(m)).ToListAsync(); |
@jvelezc Note that this issue is only about the ability to pass database provider DbParameters to raw SQL queries. We are using a separate issue in the backlog (#1862) to track the ability to use ad-hoc queries to materialize types that are not part of the model directly. In the meanwhile the approach explained by @prasannapattam can be used as a workaround, but it implies that there is an entity type from which you will later project your view model or DTO, and from the perspective of EF such entity has to map to a table so |
Fix #3115 - Support passing DbParameter instances to ExecuteSqlCommand and FromSql
Fix #3115 - Support passing DbParameter instances to ExecuteSqlCommand and FromSql
Thanks for this 👏 |
Two good places to look for examples of A simplified example of using (var context = new NorthwindContext())
{
var parameter = new SqlParameter
{
ParameterName = "@CustomerID",
Value = "ALFKI"
}
context.Database.ExecuteSqlCommand("[dbo].[CustOrderHist] @CustomerID", parameter)
} Likewise using (var context = new NorthwindContext())
{
var parameter = new SqlParameter
{
ParameterName = "@City",
Value = "London"
}
var customers = context.Customers
.FromSql(@"SELECT * FROM ""Customers"" WHERE ""City"" = @city", parameter)
.ToArray();
} There isn't an example of an output dbParameter in the test code, but the pattern should be fairly similar with appropriate stored procedures on the server. There are also some tests in |
Thanks appreciate that |
Thanks for the named parameters. In addition can you also implement the return as dynamic or ExpandoObject, so that there is no need to predefine the return type. |
Can you offer up a example of using a table-valued parameter for |
@divega YOU ARE THE MAN!! I was having to only support a particular operation for |
Glad it helped! 😄 |
Example:-
Instead of:
var UserType = dbcontext.Set().FromSql("dbo.SomeSproc @p0, @p1", 45, "Ada")
Use named parameters:
object[] sqlParams = {
new SqlParameter("@id", 45),
new SqlParameter("@name", "Ada")
};
var UserType = dbcontext.Set().FromSql("dbo.SomeSproc", sqlParams)
If SqlParameter is not supported then something like this would suffice:
var parameterDictionary = new Dictionary
{
{"@id", 45},
{"@name", "Ada"}
};
This would make it easier to find parameters in SQL profiler, also by using a list of named parameters there would be no need to worry about parameter order
The text was updated successfully, but these errors were encountered: