So I am attempting to use Entity Framework Core to call a stored proc and get some rows back into objects.
Following examples from the solution I was working in I had everything in place but it isn't working correctly to call the stored procedure or map the results back.
This was from a piece of code:
var list = this.context.DocumentList.FromSql<Document>("EXECUTE spSelDocsList #_iUserNumber", new { #_iUserNumber = UserId }).ToList();
Returning error:
"No mapping to a relational type can be found for the CLR type '<>f__AnonymousType23'."
After searching for this error more and trying to determine why it was returned I figured this out inadvertently.
From this stack overflow post:
No mapping exists from object type System.Collections.Generic.List when executing stored proc with parameters in EF 4.3
Turns out that passing an anonymous object for the SqlParameter will lead to this No Mapping to a relational type can be found for the CLR type '<>f__AnonymousType23'.
The fix for this to the code was simple, first put the parameter in an actual SqlParameter object. But passing that SqlParameter object wasn't working so by putting that in a List and returning that ToArray() IS accepted by the EF FromSql method.
List<SqlParameter> sqlParameters = new List<SqlParameter>();
sqlParameters.Add(new SqlParameter("#_iUserNumber", userId));
var list = context.DocumentList.FromSql<Document>("EXECUTE spSelDocsList #_iUserNumber", sqlParameters.ToArray()).ToList();
Related
This works:
string sql = $"SELECT * FROM {tableName}";
var executeSQL = db.Set<MyTableContextType>().FromSqlRaw(sql).ToList();
But this code will be accepting requests for multiple tables (past MyTableContextType). Rather than hardcoding MyTableContextType, I'd like to do something like this:
dynamic entityType = db.Model.FindEntityType(stringMyType);
string sql = $"SELECT * FROM {tableName}";
var executeSQL = db.Set<entityType>().FromSqlRaw(sql).ToList();
All of the above works, except the last line which gives this error:
'entityType' is a variable but is used like a type.
How can a variable be fed into db.Set<>?
If there is a better way, I am open to that too.
.NET Core 3.1
& EF Core 3.1
It won't work since Generics is a compile-time concern, but type from FindEntityType is a runtime concern.
In your case, extracting db.Set<MyTableContextType>().FromSqlRaw(sql).ToList() to generic method may help.
Something like
private TEntity SelectAll<TEntity>(string tableName) => db.Set<TEntity>().FromSqlRaw($"SELECT * FROM {tableName}").ToList();
Alternative way to solve it - use LINQ to SQL methods instead of raw SQL in order to select the data.
How can I update entity from expression?
I dynamically build which properties(columns) should be updated. Function that do that returns Expression<Func<T, T>> where T is entity.
I have loaded entity from database using Where and Single.
Expression<Func<T, T>> expr = this.CallVirtualMethodAndGetExpression(ModelFromRequest);
DbUser entity = this.context.Users.Where(t => t.Id == 1).Single();
some magic ??? //tried expr.Compile()(entity) but it does not work.
this.context.SaveChanges();
//use DbUser with updated properties of course.
I know I could use EF Plus (batch update), but I want to stick with SaveChanges (I need DbUser after SaveChanges and I want to avoid sending another request).
Updated:
I have entity object and expression. Now, I need to edit entity object based on expression and called SaveChanges which should update entity.
the magic line you are looking for:
var resultOfTypeT = expr.Compile().Invoke(entity)
But then entity needs to be an instance of type T , not DbUser
So this does not make sense to me.
So i cant give you exact code to compile for you, since i cant see the method signature where T is defined. and also do not know what the method signature of this.CallVirtualMethodAndGetExpression(ModelFromRequest) looks like.
But the Compile() will change the Expression<Func<T,T>> to just Func<T,T> which can then Invoke the defined functionality for Func<T,T> if you have a valid instance of T to pass to it.
Now your entity is not of type T, since it is of type DbUser So you are probably going to need to change your Method Signature or get your DbUser in a generic way or something. If you are only going to need to pass a DbUser instance, you do not need c# Generics. but cant really tell with just the current information available.
Plot:
I have a class implemented as a facade around Entity Framework DB context. It developed to maintain backward compatibility, it mimics class with same public interface, but uses DTOs instead of EF entities.
Problem:
I have next method inside class described above. See code below:
public IQueryable<T> FindBy<T>(Expression<Func<T, Boolean>> predicate) where T : BaseDto {
//GetDestinationType takes source type of some declared mapping and returns destination type
var entityType = Mapping.Mapper.GetDestinationType(typeof (T));
var lambda = Expression.Lambda(predicate.Body, Expression.Parameter(entityType));
// dbContext declared as class field and initialized in constructor
var query = dbContext.Set(entityType).Where(lambda); // <-- Cannot use non-generic expression/lambda
return query.ProjectTo<T>(mapper.ConfigurationProvider); }
I need to take Expression using DTOs as In parameter and return IQueryable where T : BaseDto as a result
I need to convert input predicate to the same predicate using EF entities as In parameter
I need to filter non-generic EF DbSet with help of dynamically created Expression (predicate)
Main question
Is it possible to filter non-generic EF DBSet with help of dynamically created Expression (predicate)
Please give me some glue or further directions if I need to use some other approach.
Problem has been solved. Solution was quite obvious. Instead of
var query = dbContext.Set(entityType).Where(lambda);
I can write
var query = dbContext
.Set(entityType)
.ProjectTo<T>(mapper.ConfigurationProvider)
.Where(predicate);
where predicate is the input parameter of FindBy() method.
This code will be successfully compiled and, what is more important, EF will build optimal query to the Database which will include Where() clause in the query body, so it won't take full set of records from DB side.
I have an entity SQL query that creates an entity based on resulting values.
The problem is the entities are not attached to the context. The web control using the ObjetQuery requires the entities be attached to the context to retrieve supporting data through navigation controls.
Manually adding the results will attach the entity to the context but the ObjectQuery is being used as a datasource. Unfortunately attaching the entities to the context manually is not an option as a Telerik control (RadGrid) requires the object query for additional functionality (Sorting, Filtering, etc).
Here is the code generating the object query (the function is a method of the generated ObjectContext):
public ObjectQuery<Invoice_Payment> getInvoicePaymentList(int PaymentID)
{
ObjectQuery<Invoice_Payment> oq = this.CreateQuery<Invoice_Payment>(#"SELECT VALUE DotNetNuke.Modules.Collections.Model.Invoice_Payment(Inv.ID, #PaymentID, IP.Amount, IP.TimeStamp, IP.LastModifiedBy, Inv.Company)
FROM Collections.Invoices As Inv Left Outer Join
Collections.Invoice_Payments As IP On IP.Invoice = Inv.ID && IP.Payment = #PaymentID Left Outer Join
Collections.Payments As P On P.ID = #PaymentID
WHERE (Inv.Invoice_Outstanding_Balance.ID is not null && Inv.Customer = P.Customer) || IP.Payment is not null
ORDER BY Inv.Document_Date
", new ObjectParameter("PaymentID", PaymentID));
oq = oq.Include("InvoiceDetails").Include("PaymentDetails");
oq.MergeOption = MergeOption.OverwriteChanges;
return oq;
}
What am I doing wrong or what could I have misconfigured for the resulting entities to not attach to the calling context?
Edit:
After a little more investigation I have found that my problem is not isolated to this one entity type but all entity types that are instantiated using Named Type Constructor. My problem is better defined as:
How can entities instantiated using the Named Type Constructor in entity SQL be attached to the context when the query is executed?
I can successfully return a model from my controller like this:
return View(lemonadedb.Messages.ToList() );
It's interpreted perfectly by my view.
Now I only want to show the messages where Messages.user == Membership.GetUser().ToString().
But when I do this:
return View(lemonadedb.Messages.Where( p => p.user == Membership.GetUser().ToString()).ToList());
I get:
'LINQ to Entities does not recognize
the method 'System.String ToString()'
method, and this method cannot be
translated into a store expression.'
I need some way to narrow down the results of the messages table.
Should I use the find() method somehow? I thought it was only for ID's.
How should I do this?
The reason you're having this issue is that Entity Framework is trying to evaluate the expression Membership.GetUser().ToString() into an SQL query. You need to create a new variable to store the value of this expression and pass it into your query. Entity Framework will then just interpret this as you expect.
The following should work:
var user = Membership.GetUser().ToString();
return View(lemonadedb.Messages.Where(p => p.user == user).ToList());
I suspect this is a very common mistake that people make when writing Entity Framework queries.