How to call MySQL stored procedure from ASP.NET Core 3.1 MySql.Data.EntityFrameworkCore - mysql

I have a stored procedure in Mysql that returns a table.
Using of old methods like _context.database.SqlQuery doesn't work anymore.
The _context.database.Execute* only contains methods that returns number of affected rows.
In my scenario I'm using scaffolding and can't create database objects from my code, but I can create classes.
The following code (and/or similar tries with Set or Query that is obsolete)
_context.Set<MyModel>().FromSql("CALL My_USP({0});", parametervalue).ToList<MyModel>();
returns an error about that the model is not in the _context because I'm scaffolding and MyModel is a class from my Models.
I'm totally lost with this and all help I can find in S.O. or Google are about EF6, that doesn't work in my case, the libraries are different.
Any workaround will be appreciated also, if this is not possible to do.

I got a solution but I will mark as answer someone that works without the old ADO.NET or change my dbcontext like this one, because will fail the next time I will do a scaffolding.
Add to protected override void OnModelCreating(ModelBuilder modelBuilder) in the context file:
modelBuilder.Entity<MyModel>().HasNoKey();
and then call:
_context.Set<MyModel>().FromSqlRaw("CALL My_USP({0});", parametervalue).ToList<MyModel>();

Related

Read list of strings from MySQL Stored Proc in .NET 6

I have a MySQL (not SQL Server) database with a Stored Procedure that returns a tabular result with one (1) column of strings.
I would like to get that result into my .NET application as some sort of IEnumerable<string> or List<string> etc.
What do?
I've tried playing with MySql.EntityFrameworkCore but get stuck quickly. Entity Framework Core either wants to generate tables based on models or models based on tables. I want neither. I just want my strings, plain and simple.
I've tried making a POCO with a single property and the [Keyless] attribute but no dice. If I define a DbSet<Poco> then the table doesn't exist, if I try to do context.Set<Poco>().FromSql('call my_stored_proc();'); then EF core complains the DbSet doesn't exist.
I'm using .NET 6 and the latest versions of above mentioned MySQL EntityFrameworkCore NuGet. Searching for answers is made harder by a lot of answers either assuming SQL Server or using older versions of EF core with methods that my EF core doesn't seem to have. And some results claim that EF core 6 doesn't work with .NET 6?
I'm also happy bypassing EF entirely if that's easier.
What you are asking for will eventually be available in EF Core 7.0 - Raw SQL queries for unmapped types.
Until then, the minimum you need to do is to define a simple POCO class with single property, register it as keyless entity and use ToView(null) to avoid EF Core associate a db table/view with it.
e.g.
POCO:
public class StringValue
{
public string Value { get; set; }
}
Your DbContext subclass:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<StringValue>(builder =>
{
builder.HasNoKey(); // keyless
builder.ToView(null); // no table/view
builder.Property(e => e.Value)
.HasColumnName("column_alias_in_the_sp_result");
});
}
Usage:
var query = context.Set<StringValue>()
.FromSqlRaw(...)
.AsEnumerable() // needed if SP call raw SQL is not composable as for SqlServer
.Select(r => r.Value);
EF is an ORM, not a data access library. The actual data access is performed by ADO.NET using db-specific providers. You don't need an ORM to run a query and receive results :
await using DbConnection connection = new MySqlConnection("Server=myserver;User ID=mylogin;Password=mypass;Database=mydatabase");
await connection.OpenAsync();
using DbCommand command = new MySqlCommand("SELECT field FROM table;", connection);
await using var reader = command.ExecuteReader();
while (await reader.ReadAsync())
Console.WriteLine(reader.GetString(0));
ADO.NET provides the interfaces and base implementations like DbConnection. Individual providers provide the data-specific implementations. This means the samples you see for SQL Server work with minimal modifications for any other database. To execute a stored procedure you need to set the CommandType to System.Data.CommandType.StoredProcedure :
using var command = new MySqlCommand("my_stored_proc", connection);
command.CommandType=CommandType.StoredProcedure
In this case I used the open source MySqlConnector provider, which offers true asynchronous commands and fixes a lot of the bugs found in Oracle's official Connector/.NET aka MySQL.Data. The official MySql.EntityFrameworkCore uses the official provider and inherits its problems.
ORMs like EF and micro-ORMs like Dapper work on top of ADO.NET to generate SQL queries and map results to objects. To work with EF Core use Pomelo.EntityFrameworkCore.MySql. With 25M downloads it's also far more popular than MySql.EntityFrameworkCore (1.4M).
If you only want to map raw results to objects, try Dapper. It constructs the necessary commands based on the query and parameters provided as anonymous objects, opens and closes connections as needed, and maps results to objects using reflection. Until recently it was a lot faster than EF Core in raw queries but EF caught up in EF Core 7 :
IEnumerable<User> users = cnn.Query<User>("get_user",
new {RoleId = 1},
commandType: CommandType.StoredProcedure);
No other configuration is needed. Dapper will map columns to User parameters by name and return an IEnumerable<T> of the desired classes.
The equivalent functionality will be added in EF Core 7's raw SQL queries for unmapped types

Accessing member function in YTable from XController

This is a general question about CakePHP 3, I have a substantial OOP background, but I'm new to PHP and am stuck using Cake for a project. I guess this revolves around conventions.
So say I have some model entity, Apple, with a matching ApplesTable class. In the ApplesTable class, I've implemented a method to find something from the database. If I was in the ApplesController, my understanding is that I could write: $this->Apples->method() and it would be fine.
However, if I want to access that method in say, the OrangesController, just typing the same thing gives me a fatal error saying "Call to a member function method() on boolean." From what I found researching, it could be something with it not being able to load the model element so the method call written above would just be producing false, creating the error.
Again, I'm newer to PHP and totally new to Cake, so some of the conventions with the framework are still a little hazy. Hopefully someone can help clear this up -- thanks!
Try loadModel(), when you need to use a model table/collection that is not the controller’s default one.
// ApplesController
loadModel("Oranges");
$this->Oranges->makeJuice();
$orange_sugar = $this->Oranges->sugar;
or if your models are associated,
// ApplesController
$this->Apples->Oranges->makeJuice();
$orange_sugar = $this->Apples->Oranges->sugar;

CPPDepend Detection of virtual function usage

I'm having a slight problem with CPPDepend's ability to detect virtual function usage. Consider the following scenario. Two classes, CParentClass and CChildClass, where CChildClass is derived from CParentClass. The CParentClass has a virtual function Test and CChildClass overrides the base class version of Test.
When it comes to usage, for various reasons I want to do something like the following:-
CChildClass * pMyChild = new CChildClass();
CParentClass * pParentClass = (CParentClass*)pMyChild;
int B = pParentClass->Test();
delete pParentClass;
This results in pMyChild's Test function being called, as desired, yet CPPDepend doesn't detect this and claims that the code is never reached. If I add the word "virtual" to the Test function header in CChildClass (in addition to the one already in CParentClass) then CPPDepend claims everything is ok.
Can anyone shed some light on this for me please as it feels wrong that I should have to put virtual in the derived class function as well as the base class function.
A similar issue can be seen with CDialog destructors in derived classes. Without the virtual in the derived class destructor declaration, CPPDepend complains.
Thanks for any help you can give.
Regards
Neil.
CppDepend do a static analysis not a dynamic one, and give the dependencies from a static point of view and it's more interesting. Indeed what's important is the dependency related to the design choices, for example in your case the object is declared as CParentClass, so the method is coupled with the contract of CParentClass, and in the runtime it could invoke a method from child classes.

C# and LuaInterface: How to add table entries to a C# object in Lua

I use SharpLua with MonoDevelop. I created a class on C# side, which should be usable from Lua. That's works fine, I can access all fields from Lua. It's very easy.
public class Test {
public string Name;
}
could be access from Lua with
print(test.Name)
Now, I want to create new fields by Lua. In Lua it should look like
test.abc = "A string"
print(test.abc)
But this didn't work. I get an error in the ObjectTranslator. So I couldn't extend the table from Lua. I didn't want to access this new entries from C#. It should only be possible to create them.
Is there an other way to achieve this? Could I create a class from LuaTable and insert this to Lua?
lua["NewLuaTable"] = new ClassFromLuaTable;
and than use in Lua
NewLuaTable.abc = "A string"
print(NewLuaTable.abc);
But than, how did I get notifications, that something I want to know is changed in the LuaTable (NewLuaTable.Name is changed)?
Thank you for your help.
Ok, I found it by myself.
You could extend C# classes from Lua with the functions get_Item() and set_Item(). These both functions are the same as __index and __newindex in Lua metatables. So you could create a Dictionary table in C# and fill it in the set_Item() function. If LuaInterface didn't find an entry in the class, it calls get_Item() to look, if it could get the value on this way. There you could look into your table, if it is a valid key-value-pair.

EF4.1 ConnectionString.ProviderName returning a different class

I have been trying to retrofit an excellent implementation of EF that I found here. Unfortunately the code was written for code first implementation and I am using model first since I already have the database up and running with another application.
In the ObjectContextBuilder.cs file is the following method:
public ObjectContextBuilder(string connectionStringName, string[] mappingAssemblies, bool recreateDatabaseIfExists, bool lazyLoadingEnabled)
{
this.Conventions.Remove<IncludeMetadataConvention>();
_cnStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
_factory = DbProviderFactories.GetFactory(_cnStringSettings.ProviderName);
_recreateDatabaseIfExists = recreateDatabaseIfExists;
_lazyLoadingEnabled = lazyLoadingEnabled;
AddConfigurations(mappingAssemblies);
}
I assume the EDMX would contain the mappings that the previous method requires so I am attempting to add a simaliar method that would take in an ObjectContext of the EDMX like this:
public ObjectContextBuilder(string connectionStringName, ObjectContext context, bool recreateDatabaseIfExists, bool lazyLoadingEnabled)
{
this.Conventions.Remove<IncludeMetadataConvention>();
_cnStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
_factory = DbProviderFactories.GetFactory(_cnStringSettings.ProviderName);
_recreateDatabaseIfExists = recreateDatabaseIfExists;
_lazyLoadingEnabled = lazyLoadingEnabled;
}
And here is the calling method:
ObjectContextManager.InitStorage(new SimpleObjectContextStorage());
var context = ((IObjectContextAdapter)new SidekickEntities());
ObjectContextManager.Init("SidekickEntities", context.ObjectContext, true);
When execution gets to assigning _factory I get an error that states:
Unable to find the requested .Net Framework Data Provider. It may not be installed.
When I look at _cnStringSettings, the Provider is System.Data.SqlClient but when assigning _factory the _cnStringSettings.ProviderName is System.Data.EntityClient.
I assume this is because I am trying to use the Entity generated by the EDMX and would like to know if there is a way to get my new method to work. I am fairly new to the EF framework and am still in a steep learning curve so please let me know if I am completely off base on what I am trying.
Here is the connection string as it is stored in App.Config
<add name="SidekickEntities" connectionString="metadata=res://SidekickModel/SidekickModel.csdl|res://SidekickModel/SidekickModel.ssdl|res://SidekickModel/SidekickModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=percepsrvr;Initial Catalog=Sidekick;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
Having an existing database doesn't mean you have to use model first (fortunately). See Scott Gu's Using EF “Code First” with an Existing Database and the TechEd 2011 screencast Code First Development in Microsoft ADO.NET Entity Framework 4.1 for details. Worked pretty well for me.
I found it very painful to use EF Model First for things it doesn't provide easily. It gets ugly very fast, especially when messsing with the EDMX.
In case any comes across this post I found a solution to the problem which was to call an existing method in the code as follows:
_employeeRepository = new GenericRepository(new SidekickEntities());
GenericRepository is an object in the code that would take a DbContext directly.