【问题标题】:How do I properly determine the relationships in Entity Framework from metadata classes?如何从元数据类正确确定实体框架中的关系?
【发布时间】:2021-01-11 14:59:20
【问题描述】:

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

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

因此,从这个错误的外观来看,我需要配置关系,但我不确定如何通过元数据来做到这一点,因为 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
}

我知道,当涉及标准化时,它开始变得更加复杂。我该怎么办?我将如何配置关系?是否有任何好的源材料有助于元数据类,我可以在其中搭建表格并按预期存储数据?

我们将不胜感激。

【问题讨论】:

    标签: c# sql-server entity-framework metadata


    【解决方案1】:

    您需要做出一些数据库设计决策才能使其正常工作。对于那个特定的价格,可能应该像这样配置为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);
        }
    
    }
    

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

      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 实现的工件。

    【讨论】:

    • 嘿大卫,谢谢您的意见,我已经尝试过这样做,唯一的问题是我收到此错误:“导航 'TotalSalesPrice' 无法添加,因为它针对的是无键实体类型'价格'。导航只能定位带有键的实体类型。”,即使我在模型构建器中设置了 HasNoKey()
    • 唯一的事情是我无法更改值,因为它是元数据并且数据位于 NuGet 包中。所以你编辑的课程我无法实际编辑。
    • 您可以在不使用 Fluent API 修改源类型的情况下执行此操作。查看更新的答案。
    猜你喜欢
    • 2023-03-25
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    相关资源
    最近更新 更多