È possibile mappare le funzioni con valori di tabella in EF6 senza edmx? Il problema è che le colonne nel database sono denominate in modo diverso rispetto all'applicazione.
La mia applicazione come esempio semplificato.
L' utente della tabella su SQL Server 2016:
User
Id (int, Identity, PK)
Name (nvarchar(255)
La funzione valutata tabella GetUser (id) in SQL Server 2016:
CREATE FUNCTION [dbo].[GetUser](@ID int)
RETURNS TABLE
AS
RETURN
(
SELECT *
FROM dbo.User
WHERE Id = @ID
);
Io uso il seguente pacchetto di nuget:
Install-Package EntityFramework.CodeFirstStoreFunctions
L'oggetto correlato in C #:
public class User
{
[Key]
public int Id { get; set; }
[Column("Name")]
public string UserName { get; set; }
}
Il database impostato nella mia classe DbContext:
public DbSet<User> Users { get; set; }
La mia configurazione utente con mappatura di colonne:
private void ConfigureUser(EntityTypeConfiguration<User> configuration)
{
configuration.ToTable("User");
configuration.HasKey(user => user.Id);
configuration.Property(user => user.Id).HasColumnName("Id").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
configuration.Property(user => user.UserName).HasColumnName("Name");
}
La mia stored procedure (TVF):
[DbFunction(nameof(ApplicationDb), "GetUser")]
public virtual IQueryable<User> GetUser(Nullable<int> id)
{
var idParameter = id.HasValue ?
new ObjectParameter("ID", id) :
new ObjectParameter("ID", typeof(int));
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<User>("[GetUser](@ID)", idParameter);
}
Il metodo OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (modelBuilder == null)
{
throw new ArgumentNullException(nameof(modelBuilder));
}
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Add(new CodeFirstStoreFunctions.FunctionsConvention<MyDbContext>("dbo"));
this.ConfigureUser(modelBuilder.Entity<User>());
// ...
}
Il mio problema è la seguente riga:
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<User>("[GetUser](@ID)", idParameter);
La funzione valutata tabella prevede un tipo con proprietà come la colonna della tabella. L'ortografia corretta è necessaria, quindi ho bisogno di una mappatura. È un database esterno, quindi non posso modificare le colonne in SQL Server. Il progetto non consente di utilizzare il modello edmx.
Non voglio creare il seguente tipo:
public class GetUserResult
{
public int Id { get; set; }
public string Name { get; set; }
}
Eccezione: nome colonna non valido "UserName".
StackTrace:
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
System.Data.SqlClient.SqlDataReader.get_MetaData()
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
Come è possibile?
Un mapping manuale centrales tra il nome della colonna della tabella e il nome della proprietà delle entità non costituirebbe un problema. Grazie
Non si desidera modificare l'oggetto e non è possibile modificare il database, ma è comunque possibile modificare la query. Prova a nominare le colonne nel risultato della funzione con valori di tabella:
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<User>(
"SELECT Id, Name AS UserName FROM [GetUser](@ID)", idParameter
);