【问题标题】:Wrong id generation with Postgres使用 Postgres 生成错误的 id
【发布时间】:2021-10-31 15:18:48
【问题描述】:

我正在制作一个 Web 应用程序,作为数据库提供商,我使用 postgresql 和 Ef Core 作为 ORM。我有两个班级:

public class Price
{
    public int PriceId { get; set; }
    public DateTime TimeStamp { get; set; }
    public double Value { get; set; }
    public int CompanyId { get; set; }

    public virtual Company Company { get; set; }
}


public class Company
    {
        public Company()
        {
            Prices = new HashSet<Price>();
        }

        public int CompanyId { get; set; }
        public string Acronym { get; set; }
        public string FullName { get; set; }

        public virtual ICollection<Price> Prices { get; set; }
    }

我的问题是,每当我尝试为第一家公司添加一些记录时:

var company = Context.Companies.FirstOrDefault(c => c.CompanyId == 1);
company.Prices.Add(new Price {Value = 123.45, TimeStamp = DateTime.Now});

然后是另一个

var company = Context.Companies.FirstOrDefault(c => c.CompanyId == 2);
company.Prices.Add(new Price {Value = 123.45, TimeStamp = DateTime.Now});

代替:

CompanyId | PriceId | TimeStamp | Value
-------------------------------------------
1 | 1 | foo | bar
1 | 2 | foo | bar
2 | 1 | foo | bar
2 | 2 | foo | bar

我明白了:

CompanyId | PriceId | TimeStamp | Value
-------------------------------------------
1 | 1 | foo | bar
1 | 2 | foo | bar
2 | 3 | foo | bar
2 | 4 | foo | bar

我的 Pgadmin 4 配置:

Companies table - CompanyId configuration

Prices table - CompanyId and PriceId configuration

【问题讨论】:

  • 这是意料之中的。 ID 与公司没有任何关系,因此它们必须是全球唯一的。您是否有特定的原因希望它们与众不同?可以使用组合键或自定义逻辑,但通常不需要特定的 ID
  • 我希望 CompanyId 和 PriceId 组成一个复合键。我不知道我是否设法做到了,所以我放置了配置的屏幕截图。我必须承认,这样的列举在清晰方面确实很有帮助。我想从外部 API 解析有关价格的信息,并避免所有 PriceId 不同的情况会非常好。我会避免使用难以阅读的大数字,并拥有漂亮、易于阅读、有意义的 PriceId。
  • 此类考虑不应在数据建模中发挥作用。只有健全的规范化和适当的关系。 PriceId 是所谓的代理键,它的值无关紧要。即使 Price 需要有一个 identifying relationship 到 Company,PriceId 也不必为了可读性而在 CompanyId 内递增。实现这种模式也更加困难。
  • 好的,我明白了。我必须承认,经过重新考虑,仅仅为了可读性而增加另一列听起来毫无意义。谢谢你的关系线程。我会读完所有的。感谢您宝贵的时间,先生们:)

标签: c# postgresql entity-framework


【解决方案1】:

你有一个正确的结果。 PriceId 应该递增,因为它是一个自动递增字段。但是使用错误的算法来添加新项目。如果您需要一起添加新公司和新价格,通常会使用此算法。在这种情况下,它将自动为 Price 分配一个新的 CompanyId。但是在您的情况下,您根本不需要此代码,因为它只会额外访问 db 服务器并影响性能和网络流量。删除此代码

 var company =Context.Companies.FirstOrDefault(c => c.CompanyId ==1);
//and
var company = Context.Companies.FirstOrDefault(c =>public c.CompanyId ==2);

就够了

Context.Prices.Add(new Price { CompanyId=1, Value = 123.45, TimeStampValue = DateTime.Now});
Context.Prices.Add(new Price { CompanyId=2, Value = 123.45, TimeStampValue = DateTime.Now});

或许更好

Context.Prices.AddRange( new Price[]
{ 
new Price {CompanyId=1, Value=123.45, TimeStamp= DateTime.Now},
new Price {CompanyId=2, Value=123.45, TimeStamp= DateTime.Now}
});

你有一对多的关系,但如果你需要多对多的关系,你将不得不在你的价格类中将公司更改为公司列表

public class Price
{
    public int PriceId { get; set; }
    public DateTime TimeStamp { get; set; }
    public double Value { get; set; }
  
    public virtual ICollection<Company> Companies { get; set; }
}

如果您使用的是 ef core net5+ ,则 ef 将为您创建一个额外的表,否则您必须像这样手动创建它

public class CompanyPrice
{
public int CompanyId {get; set;}
public int PriceId {get; set;}
public virtual Company Company {get; set;}
public  virtual Price Price {get; set;}
}

【讨论】:

  • 不幸的是,它没有帮助:/ 也许是 postrges 配置问题?
  • 很抱歉,现在的错误是什么?
  • 还是一样。 PriceId 中的值不断增加。
  • 塞尔吉,这一切都离题了。
  • 是的,这是一个正确的结果。 PriceId 应该递增,因为它是自动递增字段。
【解决方案2】:

我曾经也遇到过这种情况。当首先使用代码创建数据库时,其中一个值必须是 ID。作为一种可能的解决方案,我不保证它会起作用,移动

public int CompanyId { 获取;放; }

到你班级的顶部并修改如下:

> using System.ComponentModel.DataAnnotations;
>     public class Price
>     {
>         [Required]
>         public int CompanyId { get; set; }
>         public int PriceId { get; set; }
>         public DateTime TimeStamp { get; set; }
>         public double Value { get; set; }
>         
>     
>         public virtual Company Company { get; set; }
>     }

希望对你有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-19
    • 2014-12-21
    相关资源
    最近更新 更多