C# EF4.1-Fluent API-SqlQuery-调用存储过程时的配置映射-数据读取器与指定的实体类型不兼容

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

该场景——有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; 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实际上通过使用函数导入使存储过程的使用变得非常简单

  • 转到从数据库更新模型

  • 在“添加”屏幕中,找到要使用的存储过程,并选中它旁边的复选框

  • 单击finish

  • 右键单击EF设计图面并转到“添加”>“功能导入”

  • 选择要映射的进程

  • 单击“获取列信息”

  • 单击生成新的“复杂类型”。(或者,如果已映射实体,则可以返回该实体的实例,而不是复杂类型。)

  • 单击“确定”。你完了

  • 添加函数导入后,您将在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);