asp.net-mvc - 实体框架 - 错误:必须显式配置此关联的主体端
问题描述
我有一个建立在 ASP.NET MVC 5 框架之上的项目。我正在使用 Entity Framework 6.2 来访问我的数据库中的数据。
我有以下两个模型
public class Entity<T> where T : struct
{
[Key]
public T Id { get; set; }
}
public class User : Entity<int>
{
public string FirstName { get; set; }
public int CategoryId { get; set; }
// more properties removed for the sake of simplicity
public virtual Category Category { get; set; }
}
public class Category : Entity<int>
{
public string Name { get; set; }
}
这是我从数据库上下文访问用户的方式。
User user = await DbContext.Users.FirstAsync(10);
但是,我收到以下意外异常。
无法确定类型“类别”和“用户”之间关联的主体端。此关联的主体端必须使用关系流式 API 或数据注释显式配置。
我尝试向属性添加[ForeignKey]
属性,Category
但这也不起作用:
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
我也尝试添加InverseProperty
属性
[ForeignKey("CategoryId")]
[InverseProperty("Id")]
public virtual Category Category { get; set; }
但是反向属性注释会引发以下错误:
无法将属性“Id”配置为导航属性。该属性必须是有效的实体类型,并且该属性应该具有非抽象的 getter 和 setter。对于集合属性,该类型必须实现 ICollection,其中 T 是有效的实体类型。
什么可能导致此问题?我该如何解决?
解决方案
我无法复制(EF 6.4):
using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace Ef6Test
{
public class Entity<T> where T : struct
{
[Key]
public T Id { get; set; }
}
public class User : Entity<int>
{
public string FirstName { get; set; }
public int CategoryId { get; set; }
// more properties removed for the sake of simplicity
public virtual Category Category { get; set; }
}
public class Category : Entity<int>
{
public string Name { get; set; }
}
public class Db : DbContext
{
public Db(string constr) : base(constr)
{ }
public DbSet<User> Users { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
class Program
{
static void Main(string[] args)
{
var constr = "server=localhost;database=ef6test;integrated security=true";
using var db = new Db(constr);
db.Database.Delete();
db.Database.Log = msg => Console.WriteLine(msg);
db.Database.Initialize(true);
var u = new User();
u.Category = new Category();
db.Users.Add(u);
db.SaveChanges();
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
}
输出
Opened connection at 3/26/2020 5:57:48 PM -05:00
Started transaction at 3/26/2020 5:57:48 PM -05:00
CREATE TABLE [dbo].[Categories] (
[Id] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
CONSTRAINT [PK_dbo.Categories] PRIMARY KEY ([Id])
)
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 15 ms with result: -1
CREATE TABLE [dbo].[Users] (
[Id] [int] NOT NULL IDENTITY,
[FirstName] [nvarchar](max),
[CategoryId] [int] NOT NULL,
CONSTRAINT [PK_dbo.Users] PRIMARY KEY ([Id])
)
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 8 ms with result: -1
CREATE INDEX [IX_CategoryId] ON [dbo].[Users]([CategoryId])
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 7 ms with result: -1
ALTER TABLE [dbo].[Users] ADD CONSTRAINT [FK_dbo.Users_dbo.Categories_CategoryId] FOREIGN KEY ([CategoryId]) REFERENCES [dbo].[Categories] ([Id]) ON DELETE CASCADE
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 9 ms with result: -1
CREATE TABLE [dbo].[__MigrationHistory] (
[MigrationId] [nvarchar](150) NOT NULL,
[ContextKey] [nvarchar](300) NOT NULL,
[Model] [varbinary](max) NOT NULL,
[ProductVersion] [nvarchar](32) NOT NULL,
CONSTRAINT [PK_dbo.__MigrationHistory] PRIMARY KEY ([MigrationId], [ContextKey])
)
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 8 ms with result: -1
INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
VALUES (N'202003262257478_InitialCreate', N'Ef6Test.Db', 0x1F...
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 9 ms with result: 1
Committed transaction at 3/26/2020 5:57:48 PM -05:00
Opened connection at 3/26/2020 5:57:48 PM -05:00
Started transaction at 3/26/2020 5:57:48 PM -05:00
INSERT [dbo].[Categories]([Name])
VALUES (NULL)
SELECT [Id]
FROM [dbo].[Categories]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 10 ms with result: SqlDataReader
INSERT [dbo].[Users]([FirstName], [CategoryId])
VALUES (NULL, @0)
SELECT [Id]
FROM [dbo].[Users]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- @0: '1' (Type = Int32)
-- Executing at 3/26/2020 5:57:48 PM -05:00
-- Completed in 20 ms with result: SqlDataReader
Committed transaction at 3/26/2020 5:57:48 PM -05:00
Closed connection at 3/26/2020 5:57:48 PM -05:00
Hit any key to exit