將.Net Framework中幾段使用EF相關的代碼移植到.NET的項目中,本想省點事,結果碰到莫名的故障,導致浪費不少時間來解決問題。
有兩個模型使用Scarffold-Context從數(shù)據(jù)庫中生成,示例如下(均作了適當簡化):
//用戶表模型
public partial class User
{
public long Id { get; set; }
public bool Enabled { get; set; }
public string Login { get; set; } = null!;
public string Password { get; set; } = null!;
public string? Display { get; set; }
}
//角色表模型
public partial class Role
{
public long Id { get; set; }
public string Code { get; set; } = null!;
public string Display { get; set; } = null!;
public string? Description { get; set; }
}
//用戶與角色的關聯(lián)表模型
public partial class UserRole
{
public long Id { get; set; }
public long UserId { get; set; }
public long RoleId { get; set; }
}
在使用下面的代碼進行Role表的所有數(shù)據(jù)的訪問時,突然出現(xiàn)如圖錯誤:
var roles = DbContext.Roles.ToList();

圖1. 奇怪的錯誤出現(xiàn):無效的列名'UserId'
然而,我們的Role模型里根本沒有涉及任何字段名為UserId,查詢SQL Server端,確實在執(zhí)行這一句查詢的時候,發(fā)送過去的查詢是:
SELECT [r].[ID], [r].[Code], [r].[Description], [r].[Display], [r].[UserId]
FROM [Role] AS [r]
ORDER BY [r].[Code]
看起來是EF在屁股后面加了個[r].[UserId]。
研究了很久,終于找到擴展模型User的分部類里,添加了一個屬性:
private ObservableCollection<Role> roles = [];
public ObservableCollection<Role> Roles
{
get
{
if (roles.Count == 0)
{
var db = DbContext ?? AppHelper.DbContext;
var rs = db.Roles.ToList();
foreach (var r in rs)
{
r.IsSelected = db.UserRoles.Any(p => p.UserId == Id && p.RoleId == r.Id);
}
var rls = rs.OrderBy(o => o.Code);
foreach (var role in rls)
{
roles.Add(role);
}
}
return roles;
}
}
要注意的是,在.Net Framework的EF中,并不需要明確聲明屬性與數(shù)據(jù)庫字段沒映射關系,而在.NET中,則需要用[NotMapped]明確聲明,這里忘記打上這個標記,所以Scaffold-Context在生成模型的時候,認為User跟Role有一個一對多的映射關系,所以它自動幫我“運作”了一下,給Role模型加了個隱式屬性(Shadow Property)UserId。解決辦法就是在這個屬性前面標上[NotMapped]就解決了。
如下所示:
private ObservableCollection<Role> roles = [];
[NotMapped]
public ObservableCollection<Role> Roles
{
get
{
if (roles.Count == 0)
{
var db = DbContext;
var rs = db.Roles.ToList();
foreach (var r in rs)
{
r.IsSelected = db.UserRoles.Any(p => p.UserId == Id && p.RoleId == r.Id);
}
var rls = rs.OrderBy(o => o.Code);
foreach (var role in rls)
{
roles.Add(role);
}
}
return roles;
}
}