如何根据元数据 类 正确确定 Entity Framework 中的关系?

How do I properly determine the relationships in Entity Framework from metadata classes?

我目前正在使用一个收集 API 数据的包 (Crayon API NuGet Package),但是,我正在努力通过 Entity Framework 来实现它。我正在从 Crayon 中提取数据,我想将其存储到数据库中,代码很好,只是 entity framework 部分没有按我希望的那样工作。当我 运行 迁移时,我收到此错误:

“无法确定类型 'Price' 的导航 'BillingStatement.TotalSalesPrice' 表示的关系。要么手动配置关系,要么使用 '[ 忽略此 属性 NotMapped]' 属性或在 'OnModelCreating' 中使用 'EntityTypeBuilder.Ignore'。"

所以从这个错误的外观来看,我需要配置关系,但我不确定如何通过元数据来做到这一点,因为 API 数据和 classes 设置在包(元数据)。但这是我使用的 Entity Framework 模型。

public class CrayonDbContext : DbContext
    {
        private const string connectionString = @"myserver";

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(connectionString);
        }

        public DbSet<BillingStatement> BillingStatements { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

            modelBuilder.Entity<AddressData>().HasNoKey();
            modelBuilder.Entity<Price>().HasNoKey();
        }
    }

这是它正在使用的元数据中的 BillingStatement class。

namespace Crayon.Api.Sdk.Domain.Csp
{
    public class BillingStatement
    {
        public BillingStatement();

        public int Id { get; set; }
        public Price TotalSalesPrice { get; set; }
        public ObjectReference InvoiceProfile { get; set; }
        public ObjectReference Organization { get; set; }
        public DateTimeOffset StartDate { get; set; }
        public DateTimeOffset EndDate { get; set; }
        public ProvisionType ProvisionType { get; set; }
    }
}

现在这里是先前显示的帐单 class 中引用的 classes。

public class Price
{
    public Price();

    public decimal Value { get; set; }
    public string CurrencyCode { get; set; }
}

public class ObjectReference
{
    public ObjectReference();

    public int Id { get; set; }
    public string Name { get; set; }
}

public enum ProvisionType
{
    None = 0,
    Seat = 1,
    Usage = 2,
    OneTime = 3,
    Crayon = 4,
    AzureMarketplace = 5
}

我知道当涉及规范化时,它开始变得更加复杂。我会用这个做什么?我将如何配置关系?是否有任何好的来源 material 可以帮助处理元数据 classes,我可以在其中搭建表格并按预期存储数据?

如有任何帮助,我们将不胜感激。

您需要做出一些数据库设计决策才能使其正常工作。对于那个特定的价格,应该像这样配置为 Owned Entity Type

public class BillingStatement
{
    public int Id { get; set; }
    public Price TotalSalesPrice { get; set; }
    public ObjectReference InvoiceProfile { get; set; }
    public ObjectReference Organization { get; set; }
    public DateTimeOffset StartDate { get; set; }
    public DateTimeOffset EndDate { get; set; }
    public ProvisionType ProvisionType { get; set; }
}

public class ObjectReference
{
    public int Id { get; set; }
    public string Name { get; set; }
}
public enum ProvisionType
{
    None = 0,
    Seat = 1,
    Usage = 2,
    OneTime = 3,
    Crayon = 4,
    AzureMarketplace = 5
}

public class Price
{

    public decimal Value { get; set; }
    public string CurrencyCode { get; set; }
}
public class Db : DbContext
{

    public Db() : base()
    {

    }

    private static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
    {
        builder.AddFilter((category, level) =>
           category == DbLoggerCategory.Database.Command.Name
           && level == LogLevel.Debug).AddConsole();
    });

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        var constr = "Server=localhost; database=efcore5test; integrated security = true; TrustServerCertificate=true";

        optionsBuilder.UseLoggerFactory(loggerFactory)
                      .UseSqlServer(constr, o => o.UseRelationalNulls());


        base.OnConfiguring(optionsBuilder);
    }

    
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<BillingStatement>().OwnsOne<Price>( s => s.TotalSalesPrice);
        modelBuilder.Entity<BillingStatement>().OwnsOne<ObjectReference>(s => s.InvoiceProfile);
        modelBuilder.Entity<BillingStatement>().OwnsOne<ObjectReference>(s => s.Organization);

        base.OnModelCreating(modelBuilder);
    }

}

这将创建一个像这样的 table:

  CREATE TABLE [BillingStatement] (
      [Id] int NOT NULL IDENTITY,
      [TotalSalesPrice_Value] decimal(18,2) NULL,
      [TotalSalesPrice_CurrencyCode] nvarchar(max) NULL,
      [InvoiceProfile_Id] int NULL,
      [InvoiceProfile_Name] nvarchar(max) NULL,
      [Organization_Id] int NULL,
      [Organization_Name] nvarchar(max) NULL,
      [StartDate] datetimeoffset NOT NULL,
      [EndDate] datetimeoffset NOT NULL,
      [ProvisionType] int NOT NULL,
      CONSTRAINT [PK_BillingStatement] PRIMARY KEY ([Id])
  );

您可能还想用目标对象的适当导航属性替换 ObjectReference 对象,因为这似乎是您可能不想要的 API 实现的产物你的数据库。