C# 8 - Auto Interface Implementation + Default interface methods Support
keerthirajap opened this issue · comments
Please provide support for executing code inside Default interface methods in c# 8 along with Auto Interface Implementation. When I tried it executing SQL inside interface method throw error.
InvalidOperationException: The stored procedure 'GetBeerByTypeDefault' doesn't exist
InvalidOperationException: The stored procedure 'GetBeerByTypeDefault' doesn't exist.
Insight.Database.Providers.Default.SqlParameterHelper.DeriveParameters(SqlCommand cmdToPopulate)
Insight.Database.SqlInsightDbProvider.DeriveParametersFromStoredProcedure(IDbCommand command)
Insight.Database.Providers.InsightDbProvider+<>c__DisplayClass12_0.<DeriveParameters>b__0(IDbConnection _)
Insight.Database.DBConnectionExtensions.ExecuteAndAutoClose<T>(IDbConnection connection, Func<IDbConnection, IDbCommand> getCommand, Func<IDbCommand, IDataReader, T> translate, CommandBehavior commandBehavior)
Insight.Database.Providers.InsightDbProvider.DeriveParameters(IDbCommand command)
Asp.Net Core 3.0 + MVC, Insight.Database 6.2.10
Steps to reproduce
IBeerRepository.cs
public interface IBeerRepository : IDbConnection
{
public IDbConnection GetConnection();
[Sql("SELECT * FROM Beer")]
Task<IList<Beer>> GetBeerByType(); // This works perfect
Task<IList<Beer>> GetBeerByTypeDefault()
{
return GetConnection().QueryAsync<Beer>("SELECT * FROM Beer"); //Throws error
}
}
Beer.cs
public class Beer
{
public int ID;
public string Type;
}
HomeController.cs
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IBeerRepository _IBeerRepository;
public HomeController(ILogger<HomeController> logger)
{
DbConnection c = new SqlConnection("Data Source=.;Initial Catalog=InsightDatabase;Integrated Security=True");
_IBeerRepository = c.As<IBeerRepository>();
_logger = logger;
}
public async Task<IActionResult> Index()
{
var results = await _IBeerRepository.GetBeerByType();
var results1 = await _IBeerRepository.GetBeerByTypeDefault();
return View();
}
}
SQL Create table : CREATE TABLE Beer ([ID] [int], [Type] varchar(128))
Can you please clarify what you're trying to achieve here?
Default interface implementations only apply if the implementing class does not implement the methods. In a way, they are meant to provide compatibility for implementing classes if the interface changes, especially when interface owner has no control over the implementations.
In Insight's case, auto-implementing an interface means implementing the methods, in which case the default implementation will not be invoked, as per C# specification. It seems to me that your usage would suit better to an extension method, and not a default implementation.
For example:
public interface IBeerRepository : IDbConnection
{
public IDbConnection GetConnection();
[Sql("SELECT * FROM Beer")]
Task<IList<Beer>> GetBeerByType();
}
public static class BeerRepositoryExtensions
{
public static Task<IList<Beer>> GetBeerByTypeDefault(this IBeerRepository repo)
{
return repo.GetConnection().QueryAsync<Beer>("SELECT * FROM Beer");
}
}
Also, please note that you're calling the wrong Insight method. If you want to pass SQL to the server (and not a stored proc name), then you should use the API method that ends with Sql
:
Task<IList<Beer>> GetBeerByTypeDefault()
{
return GetConnection().QueryAsync<Beer>("SELECT * FROM Beer"); //Throws error
}
Should be:
return GetConnection().QueryAsyncSql<Beer>("SELECT * FROM Beer"); //Throws error
Still getting same error after changing to QueryAsyncSql
public interface IBeerRepository : IDbConnection
{
public IDbConnection GetConnection();
[Sql("SELECT * FROM Beer")]
Task<IList<Beer>> GetBeerByType(); // This works perfect
Task<IList<Beer>> GetBeerByTypeDefault()
{
return GetConnection().QuerySqlAsync<Beer>("SELECT * FROM Beer"); //Throws error
}
}
InvalidOperationException: The stored procedure 'GetBeerByTypeDefault' doesn't exist
InvalidOperationException: The stored procedure 'GetBeerByTypeDefault' doesn't exist.
Insight.Database.Providers.Default.SqlParameterHelper.DeriveParameters(SqlCommand cmdToPopulate)
Insight.Database.SqlInsightDbProvider.DeriveParametersFromStoredProcedure(IDbCommand command)
Insight.Database.Providers.InsightDbProvider+<>c__DisplayClass12_0.b__0(IDbConnection _)
Insight.Database.DBConnectionExtensions.ExecuteAndAutoClose(IDbConnection connection, Func<IDbConnection, IDbCommand> getCommand, Func<IDbCommand, IDataReader, T> translate, CommandBehavior commandBehavior)
Insight.Database.Providers.InsightDbProvider.DeriveParameters(IDbCommand command)
I was able to filter out non-abstract methods on interfaces when the code generator runs.
So now if you want to implement methods on interfaces, Insight won't override them.
Fixed in next build.