C# EF4.1-Fluent API-SqlQuery-调用存储过程时的配置映射-数据读取器与指定的实体类型不兼容
该场景——有10年历史的遗留应用程序,始终使用过程调用进行所有数据访问——需要从混合的经典ASP和.NET页面集进行彻底检查 目标-使用EF4.1和Fluent API迁移到.NET 4.0,并尽可能继续使用现有的数据库存储过程 主要类别:C# EF4.1-Fluent API-SqlQuery-调用存储过程时的配置映射-数据读取器与指定的实体类型不兼容,c#,entity-framework,stored-procedures,entity-framework-4.1,fluent-interface,C#,Entity Framework,Stored Procedures,Entity Framework 4.1,Fluent Interface,该场景——有10年历史的遗留应用程序,始终使用过程调用进行所有数据访问——需要从混合的经典ASP和.NET页面集进行彻底检查 目标-使用EF4.1和Fluent API迁移到.NET 4.0,并尽可能继续使用现有的数据库存储过程 主要类别: public class EntityBase { public int Id { get; set; } } public class User : EntityBase { public string UserName { get; s
public class EntityBase
{
public int Id { get; set; }
}
public class User : EntityBase
{
public string UserName { get; set; }
...
}
配置:
internal class ConfigurationBase<T> : EntityTypeConfiguration<T> where T : EntityBase
{
protected ConfigurationBase()
{
HasKey(t => t.Id);
}
}
internal class UserConfiguration : ConfigurationBase<User>
{
internal UserConfiguration()
{
Property(p => p.Id)
.HasColumnName("Person_Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(p => p.UserName)
.HasMaxLength(64);
ToTable("Person");
}
}
我执行以下命令:
SELECT p.Person_Id,
p.IsUser,
p.FirstName,
p.LastName,
p.UserName,
p.Email,
p.CreatedBy,
p.CreatedDate,
p.IsActive,
p.ModifiedBy,
p.ModifiedDate
FROM Person p
WHERE p.UserName = @UserName
AND p.IsActive = 1
public User AuthorizeUser(string userName)
{
SqlParameter p = new SqlParameter {
DbType = DbType.String,
ParameterName = "UserName",
Size = 64,
Value = userName
};
object[] parameters = new object[] {p};
return UnitOfWork.Context.Users.SqlQuery(CPODSStoredProcedures.User_AuthorizeUser, parameters).FirstOrDefault();
}
我得到:
数据读取器与指定的“用户”不兼容。“Id”类型的成员在数据读取器中没有同名的对应列
我已经跟踪了执行过程,并且正在读取配置,那么我是做错了什么,还是SqlQuery执行存储过程时没有注意到在这种情况下基本Id是如何重新映射到Person_Id的
提前谢谢!
G我在几个版本之前放弃了EntityFramework for nHibernate,但我非常确定您的属性Id和用户名需要标记为虚拟,就像大多数在ORMs中使用的POCO一样,否?要在EF中执行存储过程,您需要创建一个函数导入。我的公司处境相同。我们迁移到了EF,有10亿个进程需要继续使用,直到我们弃用它们为止。EF实际上通过使用函数导入使存储过程的使用变得非常简单
EntityContainter context = new EntityContainer();
User user = context.AuthorizeUser(username);
我在这里写了一篇关于这个过程的博客:
希望这有帮助 EF 4.1 Code First(即您尝试使用的fluent API)不支持存储过程
如果你想用EF来实现这一点,你别无选择,只能创建一个模型(或者等到下一个版本)。就我个人而言,我不认为这是一个问题,因为数据库已经存在,所以首先使用DB创建一个模型非常容易(将它指向那些表并说“构建这个”)。然后,您可以切换EF以使用DbContext生成器,并获得干净的POCO类来处理数据
我知道fluentapi现在是流行语兼容的闪亮东西,但它在EF的这个版本中也是全新的,而且还不是所有的东西都有。使用传统应用程序,只需使用DB First模型和POCO类生成器即可为您省去大量麻烦。映射不兼容的存储过程(或将存储过程结果集转换为新形式)创建对象模型就像使用表var和sp_executesql作为调用DbContext.SqlQuery()中提供的批处理一样简单。请参阅我的博客,以了解这方面的工作示例->
在睡梦的迷雾中,我想到了一个念头。本例中的Person类是自引用的。UpdatedBy和CreatedBy都是对自身的外键引用。当我进入办公室时,我会尝试对一个不太复杂的类运行类似的存储过程,看看问题是否会再次发生。今天我终于有时间创建一个确定的测试。我创建了一个只有两列的独立表,并创建了从基类派生的匹配对象,该基类定义了ID并将ID映射到配置类中表的ID列(Test_ID)。相同的结果-相同的错误。显然,通过SqlQuery进行的存储过程调用忽略了所有漂亮的Fluent API配置代码,而只是查找直接映射。那我现在该怎么办?stumpedI想知道实现定制物化器是否是答案——或者我们是否应该在这个应用程序中采用不同的体系结构路径,因为我们有这么多预先存在的存储过程要处理,到目前为止,让EF与它们一起工作似乎不是一件容易的任务。似乎越来越像我的最终解决方案将不得不改变所有的存储过程,以使其输出符合POCO定义的内容,而不是配置定义的内容。哦,我的天哪,如果它是那么简单和明显,我很抱歉我得在墙上撞一个星期。让我测试一下,然后再给你回复!我真的为发布这样一个简单的答案感到难过,但我还是继续这么做了,因为我以前做过。。。以及忘记将单元测试类标记为公共类,这也是非常令人沮丧的。嗯,这是一个好主意,我忘记添加virtual关键字,但即使添加了它,问题仍然存在(抱歉。EF 4.1 POCO普通表属性不必标记为虚拟。导航属性可以。我没有使用建模工具。我使用的是Fluent-API。啊,好的。我没有使用Fluent-API的经验。很抱歉。我建议您试用该工具,因为它非常支持存储过程。好的,再加上Tridus的answer、 我想我正在钻研一个解决方案。如果我更改存储过程以匹配名称,那么存储过程调用会起作用……这是让我感到沮丧的事情。但事实上,我一点也不反对使用modeler(不像我这里的一些同事)-我可以容忍在数据库更改时必须刷新模型。这是我想要避免的它产生的大而重的对象。让我回顾一下DbContext生成器文章-这可能正是我需要的!完全同意“fat”对象,但我对DbContext生成器的结果非常满意。这些类是简单的部分类,更易于使用。:)仅供参考,我没有忘记赏金-我今天几乎没有时间
public User AuthorizeUser(string userName)
{
SqlParameter p = new SqlParameter {
DbType = DbType.String,
ParameterName = "UserName",
Size = 64,
Value = userName
};
object[] parameters = new object[] {p};
return UnitOfWork.Context.Users.SqlQuery(CPODSStoredProcedures.User_AuthorizeUser, parameters).FirstOrDefault();
}
EntityContainter context = new EntityContainer();
User user = context.AuthorizeUser(username);