EF4.1 - Fluent API - SqlQuery - 调用 sproc 时的配置映射 - 数据读取器与指定的实体类型不兼容
该场景 - 具有 10 年历史的遗留应用程序,始终使用过程调用来访问所有数据 - 需要对混合经典 ASP 和 .NET 页面集进行彻底修改。
目标 - 使用 EF 4.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");
}
}
上下文全部在 DbContext.OnModelCreating 中设置为:
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserConfiguration());
}
当我直接通过上下文访问数据时一切都很好,例如:
public override IQueryable<User> GetAll()
{
return UnitOfWork.Context.Users;
}
但是当我尝试使用包含以下内容的现有存储过程时:
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 的 sproc 执行没有注意在这种情况下如何将基本 Id 重新映射到 Person_Id 。
提前致谢! G
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
将不兼容的 sproc(或将 sproc 结果集转换为新形式)映射到对象模型就像使用表 var 和 sp_executesql 作为调用 DbContext.SqlQuery() 中提供的批处理一样简单。请参阅我的博客以获取实际的工作示例 ->
Mapping incompatible sproc (or transforming sproc result sets into new forms) to your object model is as easy as using a table var and sp_executesql as a batch provided in your call to DbContext.SqlQuery(). See my blog for a working example of this in action->
http://blogs.msdn.com/b/schlepticons/archive/2012/10/15/yes-you-can-execute-parameterized-sprocs-with-ef-fluent-api-code-only-and-more.aspx
EF 4.1 Code First(即:您尝试使用的流畅 API)不支持存储过程。 请参见此处。
如果您想使用 EF 来做到这一点,您别无选择,只能创建一个模型(或者可能等到下一个版本)。就我个人而言,我认为这不是问题,因为由于数据库已经存在,因此使用 DB First 创建模型非常容易(将其指向这些表并说“构建这个”)。然后,您可以切换 EF 以使用 DbContext 生成器,并获得干净的 POCO 类来处理您的数据。 这里有一个关于如何做到这一点的简单解释。
我知道流畅的 API 是现在流行语兼容的闪亮事物,但它在这个 EF 版本中也是全新的,而且还不是所有东西都存在。对于旧版应用程序,只需使用 DB First 模型和 POCO 类生成器即可为您省去很多麻烦。
EF 4.1 Code First (ie: the fluent API you're trying to use) doesn't support Stored Procedures. See here.
If you want to do this with EF, you have no choice but to create a model (or maybe wait until the next release). Personally I don't think that's a problem, because since the database already exists creating a model using DB First is really easy (point it at those tables and say "build this"). You can then switch EF to use the DbContext generator and get nice clean POCO classes to work with your data. Here's a simple explanation on how to do that.
I know the fluent API is the buzzword compliant shiny thing right now, but it's also brand new in this release of EF and not everything is there yet. With a legacy app it's going to save you a tremendous amount of headaches to simply use the DB First model and POCO class generators instead.
要在 EF 中执行存储过程,您需要创建函数导入。我的公司也有同样的情况。我们迁移到 EF,并有 10 亿个进程需要继续使用,直到我们弃用它们为止。实际上,EF 通过使用函数导入使使用存储过程变得非常容易。
转到从数据库更新模型。
在“添加”屏幕中找到您想要使用的存储过程并选中它旁边的框。
单击“完成”。
右键单击 EF 设计图面并转到“添加”> “函数导入”。
选择您想要映射的过程。
单击“获取列信息”。
单击生成新的“复杂类型”。 (或者,如果您映射了实体,则可以返回该实体的实例而不是复杂类型。)
单击“确定”。您已完成。
添加函数导入后,您将在 EF 上下文对象上拥有一个方法,例如:
我写了一篇关于此过程的博客,此处: http://www.codetunnel.com/blog/post/53/how-to-map-a-stored-procedure-to-an-entity-in-entity-framework-4
希望这有帮助!
To execute a stored procedure in EF you need to create a function import. My company is in the same boat. We migrated to EF and have a billion procs that we need to keep using until some point when we deprecate them. EF actually makes it really easy to use stored procs through the use of function imports.
Go to Update Model from Database.
In the "Add" screen find the stored procedure you wish to use and check the box next to it.
Click finish.
Right-click the EF design surface and go to "Add" > "Function Import".
Choose the proc you wish to map.
Click "Get Column Information".
Click generate new "Complex Type". (or if you have an entity mapped, you can return an instance of the entity instead of the complex type.)
Click OK. You are done.
After adding a function import you will then have a method on your EF context object, e.g.:
I wrote a blog on this process, here: http://www.codetunnel.com/blog/post/53/how-to-map-a-stored-procedure-to-an-entity-in-entity-framework-4
Hope this helps!
我在几个版本前放弃了 nHibernate 的 EntityFramework,但我很确定您的属性 Id 和 UserName 需要标记为虚拟,就像 ORM 中使用的大多数 POCO 一样,不是吗?
I abandoned EntityFramework for nHibernate a couple versions ago, but I am pretty sure your properties Id and UserName need to be flagged virtual, as with most POCOs used in ORMs, no?