为什么在从DbSet .SqlQuery映射实体时忽略了我的DbModelBuilder配置?
我有像这样的DbModel
配置:
modelBuilder.Entity() .HasKey(w => w.PersistenceKey) .Property(w => w.PersistenceKey) .HasColumnName("WishlistLineId");
我通过以下两种方法运行查询:
public IEnumerable FetchWishlistLinesUsingLogonName(string logonName) { return GetFromRawSql(@" SELECT wl.* FROM WishlistLines wl INNER JOIN Accounts a ON wl.AccountId = a.AccountId LEFT JOIN Users u ON u.AccountId = a.AccountId WHERE u.LogonName = @p0", logonName); } protected IEnumerable GetFromRawSql(string sqlQuery, params object[] parameters) { return _dbSet.SqlQuery(sqlQuery, parameters).ToList(); }
我可以通过EF将WishlistLines
“保存”到数据库中,没有任何问题。 当我运行此查询但我收到此错误:
The data reader is incompatible with the specified 'DataAccessLayer.DatabaseContext.WishlistLine'. A member of the type, 'PersistenceKey', does not have a corresponding column in the data reader with the same name.
我知道使用DbSet.SqlQuery()
会将返回的数据映射到实体,但它似乎忽略了DbModel
配置。 从错误消息中判断(猜测)正在使用错误的数据读取器。
所以:
A)我做错了什么?
B)有没有办法利用EF的DbModel
实体映射器?
实际上,执行原始SQL查询时会忽略列名映射。 这里有两个参考文献: 这个非常不满意的post只是为了好玩,但以下一个得到了EF团队的认真回答:
从http://entityframework.codeplex.com/workitem/233引用:
SqlQuery方法的设计不考虑任何映射,包括使用属性应用的映射。 它只是将结果中的列名与对象中的属性名进行匹配。 如果列名称不匹配,则需要使用列别名(SQL Server中的AS关键字)来重命名结果中的列。
我们同意,选择使SqlQuery荣誉列属性是有用的,因此我们将此问题保持打开并将其放在我们的待办事项上以供将来考虑。
因此,唯一的解决方法似乎是在SQL查询中使用显式AS
别名而不是*
,将属性名称指定为列别名:
return GetFromRawSql(@" SELECT wl.WishlistLineId AS PersistenceKey, wl.SomeOtherColumn AS SomeOtherProperty, ... ..." // ...
我找到了另一种非常干净的解决方案。 在我的模型中,我有公共属性,其中包含我想要使用的好名字,以及与数据库中名称完全相同的私有属性,并返回公共属性的getter中的私有值,如下所示:
public class KeywordsStatistic { public string Keyword { get { return lib_motcle; } } public int NumActions { get { return nbrActions; } } private string lib_motcle { get; set; } private int nbrActions { get; set; } }
当然,如果值需要更新,则需要修改,但原则是相同的……
HTH