【问题标题】:Foreign Key Generation外键生成
【发布时间】:2019-08-13 13:43:33
【问题描述】:

我想了解以下两个表结构以及“OrderId”外键是如何生成的:-

订单表:-

public class Order : BaseEntity, IAggregateRoot
    {
        private Order()
        {
            // required by EF
        }

        public Order(string buyerId, Address shipToAddress, List<OrderItem> items)
        {
            Guard.Against.NullOrEmpty(buyerId, nameof(buyerId));
            Guard.Against.Null(shipToAddress, nameof(shipToAddress));
            Guard.Against.Null(items, nameof(items));

            BuyerId = buyerId;
            ShipToAddress = shipToAddress;
            _orderItems = items;
        }
        public string BuyerId { get; private set; }
        private readonly List<OrderItem> _orderItems = new List<OrderItem>();
        public IReadOnlyCollection<OrderItem> OrderItems => _orderItems.AsReadOnly();

        public DateTimeOffset OrderDate { get; private set; } = DateTimeOffset.Now;
        public Address ShipToAddress { get; private set; }

        public decimal Total()
        {
            var total = 0m;
            foreach (var item in _orderItems)
            {
                total = item.UnitPrice * item.Units;
            }
            return total;
        }
    }

订单项表

public class OrderItem : BaseEntity
    {
        public CatalogItemOrdered ItemOrdered { get; private set; }
        public decimal UnitPrice { get; private set; }
        public int Units { get; private set; }

        protected OrderItem()
        { }

        public OrderItem(CatalogItemOrdered itemOrdered, decimal unitPrice, int units)
        {
            ItemOrdered = itemOrdered;
            UnitPrice = unitPrice;
            Units = units;
        }
    }

订单实体配置

public class ConfigureOrder : IEntityTypeConfiguration<Order>
    {
        public void Configure(EntityTypeBuilder<Order> builder)
        {
            var navigation = builder.Metadata.FindNavigation(nameof(Order.OrderItems));
            navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
            builder.OwnsOne(o => o.ShipToAddress);
        }
    }

订单商品实体配置

public class ConfigureOrderItem : IEntityTypeConfiguration<OrderItem>
    {
        public void Configure(EntityTypeBuilder<OrderItem> builder)
        {
            builder.OwnsOne(i => i.ItemOrdered);
            builder.Property(oi => oi.UnitPrice).IsRequired(true).HasColumnType("decimal(18,2)");
        }
    }

OrderItems 表:-

Id(PK)
ItemOrdered_CatalogItemId
ItemOrdered_ProductName
ItemOrdered_PictureUri
UnitPrice
Units
OrderId(FK)

请帮助我了解如何将 OrderId(Foreign Key) 添加到表结构中。我已经浏览了上述代码,但无法弄清楚这个 FK 是如何生成的,当我检查迁移文件 OrderId 是否反映在约束下时!

【问题讨论】:

  • 我在您的OrderItem 表中看不到ProductNamePictureUrl
  • 这些属性来自 CatalogItemOrdered,这很好,因为它们是在 configureOrderItem entitybuilder 中配置的。我的问题是 OrderId(FK) 是如何出现在表中的,因为它在项目中没有声明。然而,迁移有这个限制。因此,我想知道这种关系/关联是如何基于上述模型发生的?

标签: asp.net-mvc asp.net-core entity-framework-core


【解决方案1】:

您的导航属性是Order 实体中的OrderItems 属性。它不能映射到数据库中的等效数据类型。 EF Core 将为名为@9​​87654325@ 的外键生成一个影子属性,该属性将映射到数据库中OrderItem 表中的一个可为空的OrderId 外键列。

来自EF CoreShadow Property的介绍:

当发现关系但在依赖实体类中没有找到外键属性时,可以按照约定创建影子属性。在这种情况下,将引入影子外键属性。影子外键属性将被命名(依赖实体上的导航,指向主体实体,用于命名)。如果主键属性名称包含导航属性的名称,则名称将为 .如果依赖实体上没有导航属性,则使用主体类型名称代替它。

如果我有模型:

public class Author
{
    [Key]
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection<Book> Books { get; set; }
}
public class Book
{
    [Key]
    public int BookId { get; set; }
    public string Title { get; set; }
}

当我添加迁移时,您会看到它生成了一个AuthorId FK:

migrationBuilder.CreateTable(
    name: "Books",
    columns: table => new
    {
        BookId = table.Column<int>(nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        Title = table.Column<string>(nullable: true),
        AuthorId = table.Column<int>(nullable: true)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_Books", x => x.BookId);
        table.ForeignKey(
            name: "FK_Books_Authors_AuthorId",
            column: x => x.AuthorId,
            principalTable: "Authors",
            principalColumn: "AuthorId",
            onDelete: ReferentialAction.Restrict);
    });

更多详情请参考https://www.learnentityframeworkcore.com/conventions/one-to-many-relationship

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 2021-04-21
    • 1970-01-01
    相关资源
    最近更新 更多