如何从元数据类正确确定实体框架中的关系



我目前正在使用一个收集API数据的包(Crayon API NuGet package(,但我很难通过实体框架实现这一点。我正在从Crayon中提取数据,我想将其存储到数据库中,代码很好,只是实体框架部分没有按我的意愿工作。当我运行迁移时,我会收到以下错误:

";无法确定"Price"类型的导航"BillingStatement.TotalSalesPrice"所表示的关系。手动配置关系,或使用"[NotMapped]"特性或使用"OnModelCreating"中的"EntityTypeBuilder.ignore"忽略此属性">

因此,从这个错误来看,我需要配置关系,但我不确定如何通过元数据来实现这一点,因为API数据和类是在包(元数据(中设置的。但这是我正在使用的实体框架模型。

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类。

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; }
}
}

现在,这里是前面显示的计费语句类中引用的类。

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
}

我知道,当涉及到规范化时,它开始变得更加复杂。我该怎么办?我将如何配置关系?有没有什么好的源材料可以帮助我处理元数据类,在那里我可以构建表并按预期存储数据?

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

您需要做出一些数据库设计决策才能实现这一点。对于特定的一个价格可能应该配置为一个拥有的实体类型,如下所示:

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);
}
}

它将创建这样一个表:

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实现的工件,而您可能不希望在数据库中使用它。

最新更新