【发布时间】:2021-03-23 13:15:10
【问题描述】:
我一直在学习 ADO.NET,然后是 EF Core。我的任务是在 C# 中创建一个数据库应用程序,首先在 ADO.NET 中,然后转换该应用程序,以便它可以使用实体框架。
这是我在 ADO.NET 中的设计,看起来运行良好。
CREATE TABLE Categories (
Id INT IDENTITY,
Name NVARCHAR(50) NOT NULL,
CONSTRAINT PK_Categories
PRIMARY KEY (Id)
)
CREATE TABLE CategoryCategories (
ParentCategoryId INT,
ChildCategoryId INT,
CONSTRAINT PK_CategoryCategories
PRIMARY KEY (ParentCategoryId, ChildCategoryId),
CONSTRAINT FK_CategoryCategories_ParentCategoryId
FOREIGN KEY (ParentCategoryId)
REFERENCES Categories (Id),
CONSTRAINT FK_CategoryCategories_ChildCategoryId
FOREIGN KEY (ChildCategoryId)
REFERENCES Categories (Id)
ON DELETE CASCADE
)
CREATE TABLE Products (
Id INT IDENTITY,
ArticleNumber NVARCHAR(50) NOT NULL UNIQUE,
Name NVARCHAR(50) NOT NULL,
Description NVARCHAR(500) NOT NULL,
Price DECIMAL(18,2) NOT NULL,
CONSTRAINT PK_Products
PRIMARY KEY (Id)
);
CREATE TABLE Products_Categories (
ProductId INT,
CategoryId INT NOT NULL,
CONSTRAINT PK_Products_Categories
PRIMARY KEY (ProductId, CategoryId),
CONSTRAINT FK_ProdCats_Prods
FOREIGN KEY (ProductId)
REFERENCES Products (Id),
CONSTRAINT FK_ProdCats_Cats
FOREIGN KEY (CategoryId)
REFERENCES Categories (Id)
ON DELETE CASCADE
);
Products 和 Categories 之间的连接 - 没问题,只是两个响应类中的每一个中的 ICollection 属性。 Entity Framework 立即创建了 CategoryProducts 联结表。
在实体与其自身之间创建连接时,我遇到了障碍。我尝试简单地将迁移生成的 CategoryProducts 的所有模型构建代码复制到 CategoryCategories 的 OnModelCreating 方法中,并插入列和表的正确名称。
没有用,收到有关 CategoryCategories 处于影子模式的投诉。我已经对互联网进行了真空清洁,试图找到解决方案,但我找不到任何明确的说明。在实体框架中执行此操作真的比在常规 SQL 或 ADO.NET 中更难吗?我认为实体框架应该让事情变得更容易。
有什么建议吗?如果您需要更多信息,请告诉我。
编辑
为了清楚起见,我想我可能会添加这些类。
class Category
{
public int Id { get; protected set; }
[Required]
public string Name { get; protected set; }
public ICollection<Product> Products { get; protected set; }
// public ICollection<Category> ChildCategories { get; protected set; }
public Category(string name)
{
Name = name;
Products = new List<Product>();
// ChildCategories = new List<Category>();
}
}
class CategoryCategory
{
// EFC forced me to have an Id. Could not run Add-migr Initial without it
public int Id { get; protected set; }
[Required]
public int ParentCategoryId { get; protected set; }
[Required]
public int ChildCategoryId { get; protected set; }
public CategoryCategory(int parentCategoryId, int childCategoryId)
{
ParentCategoryId = parentCategoryId;
ChildCategoryId = childCategoryId;
}
}
class Product
{
public int Id { get; protected set; }
[Required]
public string ArticleNumber { get; protected set; }
[Required]
// EFC forcing me to have unprotected set
// Without it, I can not update articles :(
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public decimal Price { get; set; }
public ICollection<Category> Categories { get; protected set; }
public Product(string articleNumber, string name, string description, decimal price)
{
ArticleNumber = articleNumber;
Name = name;
Description = description;
Price = price;
Categories = new List<Category>();
}
public Product(int id, string articleNumber, string name, string description, decimal price)
: this(articleNumber, name, description, price)
{
Id = id;
}
}
对于这些类,EF 说 实体类型“CategoryCategories”处于阴影状态。一个有效的模型要求所有实体类型都有对应的 CLR 类型。
如果我取消注释 Category 中的 ICollection ChildCategories 部分,则 EF 会在 CategoryCategories 中创建第三列 CategoryId,这在我看来是非常不可取的。当我已经有两个类别时,为什么还要第三个 ID 指代类别?
【问题讨论】:
-
实体与自身之间建立联系的目的是什么?顺便说一句,只要要求明确,EF 就会大大变得容易。
-
目的是创建上表CategoryCategories。或者更确切地说,让 EF 创建它。正如我所说,我想在 EF 中复制 ADO.NET 设计,因此 EF 表将具有与第一个 (ADO.NET) 表完全相同的结构。
-
如你所见,它有两个外键都指向 go Categories。