简体   繁体   English

如何配置包含外键的复合主键(EF Fluent API)

[英]How to configure a composite primary key containing a foreign key (EF Fluent API)

I have a one-to-many relationship between entities Curve and Point, defined as follows: 实体Curve和Point之间有一对多的关系,定义如下:

public class Curve
{
    public Curve()
    {
        Points = new HashSet<Point>();
    }

    public int CurveId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Point> Points { get; set; }
}

And: 和:

public class Point
{
    public int Point_Num { get; set; }

    public int CurveId { get; set; }

    public double XCoord { get; set; }

    public double YCoord { get; set; }

    public virtual Curve Curve { get; set; }
}

In my context class, I configure the keys and navigation properties as follows (note that the Point entity has a composite primary key): 在我的上下文类中,我按如下方式配置键和导航属性(请注意,Point实体具有复合主键):

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

    modelBuilder.Entity<Curve>()
        .HasKey(c => c.CurveId);

    modelBuilder.Entity<Point>()
        .HasKey(p => new { p.Point_Num, p.CurveId });

    modelBuilder.Entity<Point>()
        .HasRequired(p => p.Curve)
        .WithMany(c => c.Points)
        .HasForeignKey(p => p.CurveId);

}

Somewhere else in the code, I populate the database: 在代码的其他地方,我填充数据库:

var curve = new Curve
{
    Name = "curve 1"
};

var points = new List<Point>();
points.Add(new Point
{
    XCoord = 1d,
    YCoord = 1d,
});

points.Add(new Point
{
    XCoord = 2d,
    YCoord = 2d,
});

foreach (var point in points)
{
    curve.Points.Add(point);
}

using (var dbCtxt = new MyDbContext())
{
    try
    {
        dbCtxt.Curves.Add(curve);
        dbCtxt.SaveChanges();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.StackTrace);
    }
 }

An error is thrown when SaveChanges() is called "An error occurred while updating the entries." 调用SaveChanges()时发生错误“更新条目时发生错误”。

If I define Point_Num as the primary key of Point entity, all the entities update just fine. 如果我将Point_Num定义为Point实体的主键,则所有实体都会更新。 It seems like the problem comes from the fact that the composite primary key (Point_Num, CurveId) contains a foreign key (CurveId) 似乎问题来自复合主键(Point_Num,CurveId)包含外键(CurveId)的事实

I cannot get my head around this, there is clearly something I am missing. 我无法理解这一点,显然我缺少一些东西。 Any help will be much appreciated! 任何帮助都感激不尽!

So I have done what I should have done in the first place, which is creating my tables in SQL and using the Entity Data Model Wizard to generate my entities in C# (using "Code first from database") 所以我首先完成了我应该做的事情,即在SQL中创建我的表并使用实体数据模型向导在C#中生成我的实体(使用“数据库中的代码首先”)

Doing so, I noticed that EF generated the Point entity with the following "DatabaseGeneratedOption.None" data annotations on the composite primary key: 这样做,我注意到EF在复合主键上使用以下“DatabaseGeneratedOption.None”数据注释生成了Point实体:

public partial class Points
{
    [Key]
    [Column(Order = 0)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Point_Num { get; set; }

    [Key]
    [Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Curve_Id { get; set; }

    ...

    public virtual Curve Curve { get; set; }
}

I impelemented this using Fluent API: 我使用Fluent API实现了这个目的:

modelBuilder.Entity<Point>().Property(p => p.PointId)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

In the bit of code that populates the database, I create say, 2 different "Curve" entities: 在填充数据库的代码中,我创建了两个不同的“Curve”实体:

        var curve1 = new Curve
        {
            Name = "curve 1"
        };

        var curve2 = new Curve
        {
            Name = "curve 2"
        };

I then create "Point" entities specifying PointId and CurveId. 然后我创建指定PointId和CurveId的“Point”实体。 Eg let's say I want to add one point to each curve: 例如,假设我想为每条曲线添加一个点:

var points = new List<Point>();

points.Add(new Point
{
    PointId = 1,
    CurveId = 1,
    XCoord = 1.2d,
    YCoord = 3.1d,
});

points.Add(new Point
{
    PointId = 1,
    CurveId = 2,
    XCoord = 0.5d,
    YCoord = 0.75d,
});

When adding entities to the context, it is not sufficient to add the curve1 and curve2, I also need to add the list of points previously created, EF does not upload them automatically: 在向上下文添加实体时,仅添加curve1和curve2是不够的,我还需要添加先前创建的点列表,EF不会自动上传它们:

myContext.Points.AddRange(points);
myContext.Curves.Add(curve1);
myContext.Curves.Add(curve2);
myContext.SaveChanges();

It is not an elegant solution at all. 它根本不是一个优雅的解决方案。 I was hoping there would be a more straightforward way of doing this, but that solved my problem! 我希望有一种更简单的方法可以做到这一点,但这解决了我的问题! The database is updated correctly, all the keys and foreign keys are set up properly... 数据库正确更新,所有键和外键都正确设置...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM