Entity framework core 在实体框架内核中实现ADO.NET设计
我一直在学习ADO.NET,然后是EF Core。我的任务是在C#中创建一个数据库应用程序,首先在ADO.NET中创建,然后将该应用程序转换为实体框架 这是我在ADO.NET中的设计,看起来效果不错Entity framework core 在实体框架内核中实现ADO.NET设计,entity-framework-core,Entity Framework Core,我一直在学习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 C
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
);
产品和类别之间的连接——没问题,只是两个响应类中每个类的ICollection属性。实体框架立即创建了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;
}
}
类别
{
public int Id{get;protected set;}
[必需]
公共字符串名称{get;protected set;}
公共ICollection产品{get;protected set;}
//公共ICollection子类别{get;protected set;}
公共类别(字符串名称)
{
名称=名称;
产品=新列表();
//ChildCategories=新列表();
}
}
类范畴
{
//EFC强制我拥有一个Id。没有它,无法运行Add migr Initial
public int Id{get;protected set;}
[必需]
public int ParentCategoryId{get;protected set;}
[必需]
public int ChildCategoryId{get;protected set;}
公共类别类别(int parentCategoryId、int childCategoryId)
{
ParentCategoryId=ParentCategoryId;
ChildCategoryId=ChildCategoryId;
}
}
类产品
{
public int Id{get;protected set;}
[必需]
公共字符串ArticleNumber{get;protected set;}
[必需]
//EFC强制我设置未受保护的
//没有它,我无法更新文章:(
公共字符串名称{get;set;}
[必需]
公共字符串说明{get;set;}
[必需]
公共十进制价格{get;set;}
公共ICollection类别{get;protected set;}
公共产品(字符串编号、字符串名称、字符串描述、十进制价格)
{
ArticleNumber=ArticleNumber;
名称=名称;
描述=描述;
价格=价格;
类别=新列表();
}
公共产品(int-id、string-articleNumber、string-name、string-description、十进制价格)
:此(商品编号、名称、说明、价格)
{
Id=Id;
}
}
对于这些类,EF表示实体类型“CategoryCategories”处于阴影状态。有效的模型要求所有实体类型都具有相应的CLR类型
如果我取消对Category中ICollection ChildCategories部分的注释,那么EF将在CategoryCategories中创建第三列CategoryId,这在我看来是非常不可取的。既然我已经有两个类别,为什么我还希望第三个ID引用类别
产品和类别之间的连接——没问题,只是两个响应类中每个类的ICollection属性。实体框架立即创建了CategoryProducts连接表
如果这是可行的,那么您将使用EF Core 5.0+,它增加了对隐式连接实体的多对多关系的支持,可以看出,创建这样的关系非常容易
但是您的类别类别
表示完全相同类型的关系,唯一的区别是,两个相关的端点是一个相同的实体
那么如何在两个实体之间创建这种关系呢?可以通过在每个相关实体中添加2个(!)集合导航属性来实现:
class Product
{
public ICollection<Category> Categories { get; set; }
}
class Category
{
public ICollection<Product> Products { get; set; }
}
如果您不喜欢生成的表/列名,它们都可以通过fluent API进行配置。如果您喜欢,您甚至可以创建和映射显式连接实体,并且仍然可以使用所谓的“跳过导航”的好处
但是,这两个集合导航属性是最基本的属性,是使EF核心方法更简单的东西。实体与自身之间的连接的目的是什么?顺便问一下,EF使它更容易-只要需求明确。目的是创建上表的CategoryCategories。或者更确切地说,让EF创建它。正如我所说的,我想在EF中复制ADO.NET设计,因此EF表的结构将与第一个表(ADO.NET)完全相同一个。正如你所看到的,它有两个外键都指向go类别。非常感谢!我想这解决了它。不知道我做错了什么,导致了这个额外的类别,但现在一切似乎都很好,所以这是没有意义的。再次感谢。
class Category
{
public ICollection<Category> ParentCategories { get; set; }
public ICollection<Category> ChildCategories { get; set; }
}
migrationBuilder.CreateTable(
name: "CategoryCategory",
columns: table => new
{
ChildCategoriesId = table.Column<int>(type: "int", nullable: false),
ParentCategoriesId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CategoryCategory", x => new { x.ChildCategoriesId, x.ParentCategoriesId });
table.ForeignKey(
name: "FK_CategoryCategory_Categories_ChildCategoriesId",
column: x => x.ChildCategoriesId,
principalTable: "Categories",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CategoryCategory_Categories_ParentCategoriesId",
column: x => x.ParentCategoriesId,
principalSchema: "SO14",
principalTable: "Categories",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});