EF Core - 在没有 primary/foreign 键的情况下创建关系
EF Core - create relationship without primary/foreign keys
我正在尝试将 EF 配置为在检索用户或产品时包含文档。实体文档有一个 ReferenceId 属性,它应该存储 UserId 或 ProductId。这样,当我为用户或产品保存文档时,UserId 或 ProductId 将保存到 Document.ReferenceId.
实体:
public class User
{
public string Id { get; set; }
public ICollection<Document> Documents { get; set; }
}
public class Product
{
public string Id { get; set; }
public ICollection<Document> Documents { get; set; }
}
public class Document
{
public string Id { get; set; }
public string ReferenceId { get; set; }
}
正在配置:
builder.Entity<User>(e =>
{
e.HasKey(e => e.Id);
e.Property(p => p.Id).ValueGeneratedOnAdd();
e.HasMany(e => e.Documents)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
});
builder.Entity<Product>(e =>
{
e.HasKey(e => e.Id);
e.Property(p => p.Id).ValueGeneratedOnAdd();
e.HasMany(e => e.Documents)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
});
builder.Entity<Document>(e =>
{
e.HasKey(e => e.Id);
e.Property(p => p.Id).ValueGeneratedOnAdd();
e.ToTable("Documents");
});
节省:
var user = new User { };
var userDocument = new Document { ReferenceId = user.Id };
var product = new Product { };
var productDocument = new Document { ReferenceId = product.Id };
_context.Users.Add(user);
_context.Products.Add(product);
_context.Add(userDocument);
_context.Add(productDocument);
_context.SaveChanges();
迁移:
migrationBuilder.CreateTable(
name: "Documents",
columns: table => new
{
Id = table.Column<string>(nullable: false),
ReferenceId = table.Column<string>(nullable: true),
ProductId = table.Column<string>(nullable: true),
UserId = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Documents", x => x.Id);
table.ForeignKey(
name: "FK_Documents_Products_ProductId",
column: x => x.ProductId,
principalTable: "Products",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Documents_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
我不想在文档 table 上创建 2 个外键(ProductId 和 UserId)。有没有办法让 EF 自动 link UserId 和 ProductId 到 ReferenceId?
解决它的正确方法是让 User 和 Product 继承一个基 class 并将 Id 和 Documents 属性移动到那个 class。
public class BaseObject
{
public string Id { get; set; }
public ICollection<Document> Documents { get; set; }
}
public class User : BaseObject
{
}
public class Product : BaseObject
{
}
public class Document
{
public string BaseObjectId { get; set; }
}
您可以创建多对多 table:
public class Product
{
public string Id { get; set; }
public ICollection<ProductDocument> ProductDocuments{ get; set; }
}
public class Document
{
public string ReferenceId { get; set; }
}
public class ProductDocument
{
public ICollection<Product> Products{ get; set; }
public ICollection<Document> Documents { get; set; }
}
您必须使用相同的模式为您的用户 table 创建单独的 table,即 UserDocumentes
。
我看到的唯一方法是使用 TPH 继承 (See here for more information)。
我引用并编辑了。
public enum DocumentType
{
User = 0,
Product = 1
}
public class BaseObject
{
public string Id { get; set; }
public ObjectType DocumentType{ get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
public class User : BaseObject
{
}
public class Product : BaseObject
{
}
public class Document
{
public int Id { get; set; }
public string BaseObjectId { get; set; }
public virtual BaseObject DocumentObject { get; set; }
}
通过 fluent-Api 你可以设置一个鉴别器。这样 ef core 只会为对象 Product
和 User
创建一个 table 并通过鉴别器列的值区分它们的类型。但前提是它们具有与基数 class 共享的完全相同的属性。一旦您将属性添加到其中一个子 class 中,就会创建一个新的 table(所有属性都来自 base- 和子 class)。
这是鉴别器的配置:
modelBuilder.Entity<BaseObject>()
.HasDiscriminator<DocumentType>("DocumentType")
.HasValue<User>(DocumentType.User)
.HasValue<Product>(DocumentType.Product)
这可能不是一个干净的方法(对我来说,User 和 Product 似乎不应该继承自同一个基础 class,因为它们除了与文档的关系之外不共享任何东西)。但它应该如你所愿地工作。
我正在尝试将 EF 配置为在检索用户或产品时包含文档。实体文档有一个 ReferenceId 属性,它应该存储 UserId 或 ProductId。这样,当我为用户或产品保存文档时,UserId 或 ProductId 将保存到 Document.ReferenceId.
实体:
public class User { public string Id { get; set; } public ICollection<Document> Documents { get; set; } } public class Product { public string Id { get; set; } public ICollection<Document> Documents { get; set; } } public class Document { public string Id { get; set; } public string ReferenceId { get; set; } }
正在配置:
builder.Entity<User>(e => { e.HasKey(e => e.Id); e.Property(p => p.Id).ValueGeneratedOnAdd(); e.HasMany(e => e.Documents) .WithOne() .OnDelete(DeleteBehavior.Cascade); }); builder.Entity<Product>(e => { e.HasKey(e => e.Id); e.Property(p => p.Id).ValueGeneratedOnAdd(); e.HasMany(e => e.Documents) .WithOne() .OnDelete(DeleteBehavior.Cascade); }); builder.Entity<Document>(e => { e.HasKey(e => e.Id); e.Property(p => p.Id).ValueGeneratedOnAdd(); e.ToTable("Documents"); });
节省:
var user = new User { }; var userDocument = new Document { ReferenceId = user.Id }; var product = new Product { }; var productDocument = new Document { ReferenceId = product.Id }; _context.Users.Add(user); _context.Products.Add(product); _context.Add(userDocument); _context.Add(productDocument); _context.SaveChanges();
迁移:
migrationBuilder.CreateTable( name: "Documents", columns: table => new { Id = table.Column<string>(nullable: false), ReferenceId = table.Column<string>(nullable: true), ProductId = table.Column<string>(nullable: true), UserId = table.Column<string>(nullable: true) }, constraints: table => { table.PrimaryKey("PK_Documents", x => x.Id); table.ForeignKey( name: "FK_Documents_Products_ProductId", column: x => x.ProductId, principalTable: "Products", principalColumn: "Id", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_Documents_Users_UserId", column: x => x.UserId, principalTable: "Users", principalColumn: "Id", onDelete: ReferentialAction.Cascade); });
我不想在文档 table 上创建 2 个外键(ProductId 和 UserId)。有没有办法让 EF 自动 link UserId 和 ProductId 到 ReferenceId?
解决它的正确方法是让 User 和 Product 继承一个基 class 并将 Id 和 Documents 属性移动到那个 class。
public class BaseObject
{
public string Id { get; set; }
public ICollection<Document> Documents { get; set; }
}
public class User : BaseObject
{
}
public class Product : BaseObject
{
}
public class Document
{
public string BaseObjectId { get; set; }
}
您可以创建多对多 table:
public class Product
{
public string Id { get; set; }
public ICollection<ProductDocument> ProductDocuments{ get; set; }
}
public class Document
{
public string ReferenceId { get; set; }
}
public class ProductDocument
{
public ICollection<Product> Products{ get; set; }
public ICollection<Document> Documents { get; set; }
}
您必须使用相同的模式为您的用户 table 创建单独的 table,即 UserDocumentes
。
我看到的唯一方法是使用 TPH 继承 (See here for more information)。
我引用并编辑了
public enum DocumentType
{
User = 0,
Product = 1
}
public class BaseObject
{
public string Id { get; set; }
public ObjectType DocumentType{ get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
public class User : BaseObject
{
}
public class Product : BaseObject
{
}
public class Document
{
public int Id { get; set; }
public string BaseObjectId { get; set; }
public virtual BaseObject DocumentObject { get; set; }
}
通过 fluent-Api 你可以设置一个鉴别器。这样 ef core 只会为对象 Product
和 User
创建一个 table 并通过鉴别器列的值区分它们的类型。但前提是它们具有与基数 class 共享的完全相同的属性。一旦您将属性添加到其中一个子 class 中,就会创建一个新的 table(所有属性都来自 base- 和子 class)。
这是鉴别器的配置:
modelBuilder.Entity<BaseObject>()
.HasDiscriminator<DocumentType>("DocumentType")
.HasValue<User>(DocumentType.User)
.HasValue<Product>(DocumentType.Product)
这可能不是一个干净的方法(对我来说,User 和 Product 似乎不应该继承自同一个基础 class,因为它们除了与文档的关系之外不共享任何东西)。但它应该如你所愿地工作。