cSt*_*off 5 c# sql-server entity-framework user-defined-functions entity-framework-6
可以在没有 edmx 的情况下在 EF6 中映射表值函数吗?问题是数据库中列的名称与应用程序中的列名称不同。
我的应用程序作为一个简化的例子。
SQL Server 2016 上的表用户:
User
Id (int, Identity, PK)
Name (nvarchar(255)
Run Code Online (Sandbox Code Playgroud)
SQL Server 2016 上的表值函数GetUser(id):
User
Id (int, Identity, PK)
Name (nvarchar(255)
Run Code Online (Sandbox Code Playgroud)
我使用以下 nuget 包:
CREATE FUNCTION [dbo].[GetUser](@ID int)
RETURNS TABLE
AS
RETURN
(
SELECT *
FROM dbo.User
WHERE Id = @ID
);
Run Code Online (Sandbox Code Playgroud)
C#中的相关对象:
Install-Package EntityFramework.CodeFirstStoreFunctions
Run Code Online (Sandbox Code Playgroud)
在我的 DbContext 类中设置的数据库:
public class User
{
[Key]
public int Id { get; set; }
[Column("Name")]
public string UserName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我的用户配置与列映射:
public DbSet<User> Users { get; set; }
Run Code Online (Sandbox Code Playgroud)
我的存储过程(TVF):
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");
}
Run Code Online (Sandbox Code Playgroud)
OnModelCreating 方法:
[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);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是以下几行:
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>());
// ...
}
Run Code Online (Sandbox Code Playgroud)
表值函数需要具有表列等属性的类型。正确的拼写是必要的,所以我需要一个映射。它是一个外部数据库,因此我无法更改 SQL Server 中的列。该项目不允许使用 edmx 模型。
我不想创建以下类型:
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<User>("[GetUser](@ID)", idParameter);
Run Code Online (Sandbox Code Playgroud)
例外:无效的列名“用户名”。
堆栈跟踪:
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)
Run Code Online (Sandbox Code Playgroud)
这怎么可能?
表列名称和实体属性名称之间的中心手动映射不会有问题。谢谢
Yas*_*ngh -1
您好,花了 30 分钟,但我能够将结果正确地转换为类型用户。我遵循了此处提到的相同步骤,只是 GetUser DBFunction 中的一处更改。以下是我的所有课程和结果。我希望这就是你想要的。
首先是我的上下文类:请检查 getuser 函数,我添加了 gettype.Name 函数,该函数在您的代码中不存在。
public class SampleDbContext : DbContext
{
public SampleDbContext()
: base("name=SampleDBConnection")
{
this.Configuration.LazyLoadingEnabled = true;
this.Configuration.ProxyCreationEnabled = true;
}
public DbSet<Customer> Customers { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new FunctionsConvention<SampleDbContext>("dbo"));
}
[DbFunction("SampleDbContext", "CustomersByZipCode")]
public IQueryable<Customer> CustomersByZipCode(string zipCode)
{
var zipCodeParameter = zipCode != null ?
new ObjectParameter("ZipCode", zipCode) :
new ObjectParameter("ZipCode", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext
.CreateQuery<Customer>(
string.Format("[{0}].{1}", GetType().Name,
"[CustomersByZipCode](@ZipCode)"), zipCodeParameter);
}
[DbFunction("SampleDbContext", "GetUser")]
public virtual IQueryable<User> GetUser(int? id)
{
var idParameter = id.HasValue ?
new ObjectParameter("ID", id) :
new ObjectParameter("ID", typeof(int));
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<User>(
string.Format("[{0}].{1}", GetType().Name,
"[GetUser](@ID)"), idParameter);
}
}
Run Code Online (Sandbox Code Playgroud)
我的 EF 模型类
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string ZipCode { get; set; }
}
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("Name")]
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这是我的两次迁移。我首先与客户进行测试,然后将用户添加到我的数据库上下文中,这就是我进行 2 次迁移的原因。
在上下文中添加客户时进行迁移
public override void Up()
{
CreateTable(
"dbo.Customers",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
ZipCode = c.String(),
})
.PrimaryKey(t => t.Id);
Sql(@"CREATE FUNCTION [dbo].[CustomersByZipCode](@ZipCode nchar(5))
RETURNS TABLE
RETURN
SELECT [Id], [Name], [ZipCode]
FROM [dbo].[Customers]
WHERE [ZipCode] = @ZipCode");
}
public override void Down()
{
DropTable("dbo.Customers");
Sql(@"Drop FUNCTION [dbo].[CustomersByZipCode]");
}
Run Code Online (Sandbox Code Playgroud)
在上下文中添加用户时进行第二次迁移
public override void Up()
{
CreateTable(
"dbo.Users",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
Sql(@" CREATE FUNCTION [dbo].[GetUser](@ID int)
RETURNS TABLE
AS
RETURN
(
SELECT *
FROM dbo.Users
WHERE Id = @ID
)");
}
public override void Down()
{
DropTable("dbo.Users");
Sql(@" drop FUNCTION [dbo].[GetUser] ");
}
Run Code Online (Sandbox Code Playgroud)控制台应用程序中的代码和输出:我在两个表中手动添加了一些记录来测试
| 归档时间: |
|
| 查看次数: |
2070 次 |
| 最近记录: |