I am using ASP.NET MVC 3 and EF 4.x
I have a procedure that returns a result set but the columns are not fixed (it may return 25 columns or may be 40 or 50).
How can I call this stored procedure from Entity Framework?
When I use function import it asks for an Entity. But I cannot select it as none of the columns is fixed.
Entity Framework is not the right tool for this. It is good at statically defined data structures, not at dynamic ones.
There are better tools for this. I would recommend Dapper, created by Marc Gravell. It's easy as pie. Just get the NuGet package and type something like
using Dapper;
using (var cnn = new SqlConnection(myConnectionString))
{
cnn.Open();
var p = new DynamicParameters();
p.Add("#params", "Id=21");
var results = cnn.Query(sql:"GetMyData",
param: p,
commandType: CommandType.StoredProcedure);
foreach(IDictionary<string, object> result in results)
{
// Do something here.
}
}
Query is a Dapper extension method, result is a DapperRow, which is a private class that implements IDictionary<string, object>, so you can just access your data as a dictionary per record.
Aside from being easy to use, it's lightning fast too.
Related
I have installed EF Core 5 Power Tools to Add a DB with stored procedure to an ASP.NET Core project. the models are successfully generated by Power Tools and the tables work fine; but when i try to retrieve a result set out of a stored procedure and store it to a ViewBag to display on the View, the value stored at Viewbag is weird and has nothing to do with a result set.
Here is the stored procedure code at db, which is pretty simple, just to test Power Tools:
CREATE PROCEDURE retTable (#P INT)
AS
BEGIN
SELECT * FROM STU WHERE ID=#P;
END;
Controller:
public IActionResult Index()
{
schoolContext s = new schoolContext();
schoolContextProcedures sp = new schoolContextProcedures(s);
var t = sp.retTableAsync(20); // The built is perfectly done, but the value store instead of result set is weird
ViewBag.test = t;
return View();
}
and just added a #View.Bag to the view to make sure it's displayed, Though the app's built is done successfully without any error, This is what's displayed at the View instead of ViewBag value:
System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1[System.Collections.Generic.List`1[WebApplication2.Models.DB.retTableResult],WebApplication2.Models.DB.schoolContextProcedures+d__3]
Tried to convert the result set to a list or something else but it's not working :|
Anyone know how to fix it?
The value stored in it is not "weird", its a Task.
Since your method is async, you should await for the result of the returned task, not the "return" itself, as this is only a reference to the task that is executed asynchronusly.
As martin smith mentions, just:
var t = await sp.retTableAsync(20);
Otherwise you are adding a task as the viewbag property, instead of the task result once completed
I am building an ASP.NET MVC application using the Repository pattern. A typical method in my Repository is as follows
public IList<T> Select<T>(string cacheKey, string Sql, object filter) where T: new()
{
IList<T> items = MemoryCache.Default.Get(cacheKey) as IList<T>;
if (items == null || !items.Any())
{
items = Connection.Select<T>(Sql, filter);
MemoryCache.Default.Add(cacheKey, items, DateTime.Now.AddMinutes(120));
}
return items;
}
and it is being used as follows
IEnumerable<OSADCOL> osadcols = Repository.Select<OSADCOL>("OSADCOLS__TblId=" + Id, "TBLid = #id", new { id = Id });
In the above mentioned example OSADCOL is a model in my app and represents a Table with the same name in my Database. The Connection.Select function is ORMlite function. I don't use Entity Framework for performance issues. My problem is the following. I am currently cashing the result set for future relevance but I am doing it in a hard coded way. I am caching the result set for 2 hours. It is obvious that a proper implementation would be to discard my cashed data when the OSADCOL's table data changes. It seems that I have to use SQLDependency or SQLCacheDependency. The questions are the following:
How am I going to use SQLDependency or SQLCacheDependency with this Repository?
What is the actual difference between these 2?
It is mentioned in some forums that SQLDependency creates memory leaks? Is that true? And If yes is there an alternative approach?
Any Ideas?
I am using entity framework 6 with stored procedures. Currently I deal with this problem:
Ideally I need to get data from one stored procedure. This data includes:
One Conversation (basic info) + multiple Clients (which are engaged in this conversation) + Messages from Conversation.
I think that output parameters is right way to do, but i am stuck.
So, how can I do that? And is this the right way to get rows of different data from stored procedure? I am trying to avoid a solution where I would be sending recurring data about conversation with every row of the client.
I found alternative solution with multiple result sets here and here (imho better), but this is not the answer to my question..
You can try with
static void Main(string[] args)
{
using (SchoolEntities context = new SchoolEntities())
{
var outputParameter = new ObjectParameter(“sum”, typeof(decimal));
context.SchoolBudgetForDateRange(new DateTime(2007, 1, 1),
new DateTime(2008, 1, 1),
outputParameter);
Console.WriteLine(outputParameter.Value);
}
}
where SchoolBudgetForDateRange is a stored procedure
more info here
I've noticed that in the metadata there's an object entityType but also an object enumType.
We use manager.metadataStore.getEntityType() to access the metadata of an Entity.
How can we do it for a given enum ? How would I create the enum on the client side out of the metadata ?
Also, when I assign an enum value to a property, I'd like to to it by name instead of by value.
For instance, assuming that Status is of type myEnum:
myEntity.Status = myEnum.Valid;
instead of
myEntity.Status = 1;
Does breeze have any helper function to access the values of an enum ?
This issue is still open as I write. But you might want to take a look at the work-around described in the answer to this SO question.
I am assuming that you are talking about data properties that are defined as .NET enums on the server, and you want additional metadata about these properties to be made available on the Breeze client.
Unfortunately, Breeze does not yet support any metadata on enum types other than the name of the .NET type backing the enum value. This is the 'enumType' property that will appear on any dataProperty that is backed by an .NET Enum on the server. (We do need to document this better)
Please add a feature request for this to the Breeze User Voice. It's a good idea and we do take these suggestions very seriously.
Well this is not exact solution to your question but definitely can help people who are generating metadata offline.
I am using NancyFx(No EF) + Breeze + AngularJS for my web project and generating breeze metadata offline(using EF methods at development) and then using it in js file.
I also encountered similar situation where I want to get all Enum values to bind dropdowns and to display EnumName corresponding to EnumValue(Id). I searched over net but there was not much as per my scenario.
So I have written raw JS methods
1. To extract all enums and their values(Id & Name) in a JS dictionary(associated array) from metadata.
var enumDictionary = {};
JSON.parse(window.app.metadata).schema.enumType.forEach(function (enumType) {
var newEnumValues = [];
enumType.member.forEach(function (enumValue) {
var newEnumValue = { id: enumValue.value, name: enumValue.name };
newEnumValues.push(newEnumValue);
});
enumDictionary[enumType.name] = newEnumValues;
});
I created a method to get all enum values for a specific enum. This will be used for binding a dropdown.
function GetEnumDictionary(enumName) {
return enumDictionary[enumName];
}
Another method I created to get specific Enum name on basis of value.
function GetEnumDictionaryValue(enumName, enumValueId) {
var result = null;
enumDictionary[enumName].some(function (enumValue) {
if (enumValue.id == enumValueId) {
result = enumValue.name;
return;
}
});
return result;
}
In EF4, this was not easily possible. You either had to degrade to classic ADO.NET (DataReader), use ObjectContext.Translate or use the EFExtensions project.
Has this been implemented off the shelf in EF CTP5?
If not, what is the recommended way of doing this?
Do we have to cast the DbContext<T> as an IObjectContextAdapter and access the underlying ObjectContext in order to get to this method?
Can someone point me to a good article on doing this with EF CTP5?
So i got this working, here's what i have:
internal SomeInternalPOCOWrapper FindXXX(string xxx)
{
Condition.Requires(xxx).IsNotNullOrEmpty();
var someInternalPokey = new SomeInternalPOCOWrapper();
var ctx = (this as IObjectContextAdapter).ObjectContext;
var con = new SqlConnection("xxxxx");
{
con.Open();
DbCommand cmd = con.CreateCommand();
cmd.CommandText = "exec dbo.usp_XXX #xxxx";
cmd.Parameters.Add(new SqlParameter("xxxx", xxx));
using (var rdr = cmd.ExecuteReader())
{
// -- RESULT SET #1
someInternalPokey.Prop1 = ctx.Translate<InternalPoco1>(rdr);
// -- RESULT SET #2
rdr.NextResult();
someInternalPokey.Prop2 = ctx.Translate<InternalPoco2>(rdr);
// -- RESULT SET #3
rdr.NextResult();
someInternalPokey.Prop3 = ctx.Translate<InternalPoco3>(rdr);
// RESULT SET #4
rdr.NextResult();
someInternalPokey.Prop4 = ctx.Translate<InternalPoco4>(rdr);
}
con.Close();
}
return someInternalPokey;
}
Essentially, it's basically like classic ADO.NET. You read the DbReader, advance to the next result set, etc.
But at least we have the Translate method which seemingly does a left-to-right between the result set fields and the supplied entity.
Note the method is internal.
My Repository calls this method, then hydrates the DTO into my domain objects.
I'm not 100% happy with it for 3 reasons:
We have to cast the DbContext as IObjectContextAdapter. The method Translate should be on DbContext<T> class IMO.
We have to use classic ADO.NET Objects. Why? Stored Procedures are a must have for any ORM. My main gripe with EF is the lack of the stored procedure support and this seems to not have been rectified with EF CTP5.
You have to open a new SqlConnection. Why can't it use the same connection as the one opened by the EF Context?
Hope this both helps someone and sends out a message to the EF team. We need multiple result support for SPROCS off the shelf. You can map a stored proc to a complex type, so why can't we map a stored proc to multiple complex types?