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

标签 c# entity-framework ef-fluent-api

我在实体 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; }
}

和:

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

在我的上下文类中,我按如下方式配置键和导航属性(注意 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);

}

在代码的其他地方,我填充了数据库:

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

调用 SaveChanges() 时抛出错误“更新条目时发生错误。”

如果我将 Point_Num 定义为 Point 实体的主键,则所有实体都可以正常更新。问题似乎出在复合主键(Point_Num,CurveId)包含外键(CurveId)

我无法理解这个问题,显然我缺少一些东西。任何帮助将不胜感激!

最佳答案

所以我已经完成了我首先应该做的事情,即在 SQL 中创建我的表并使用实体数据模型向导在 C# 中生成我的实体(使用“代码优先从数据库”)

这样做时,我注意到 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; }
}

我使用 Fluent API 实现了这个:

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

在填充数据库的代码中,我创建了 2 个不同的“曲线”实体:

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

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

然后我创建指定 PointId 和 CurveId 的“点”实体。例如。假设我想在每条曲线上添加一个点:

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

在上下文中添加实体时,添加曲线1和曲线2是不够的,我还需要添加之前创建的点列表,EF不会自动上传它们:

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

这根本不是一个优雅的解决方案。我希望有一种更直接的方法可以做到这一点,但这解决了我的问题!数据库更新正确,所有键和外键设置正确...

关于c# - 如何配置包含外键的复合主键(EF Fluent API),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43217491/

相关文章:

c# - 访问路径 wwwroot 被拒绝,即使我有权限

c# - ProgressBar 的颜色没有改变 c#

c# - 在 MVC EF 中导航多个关系

c# - 扩展 EF DBContext

c# - EF 6 : Removing entities results in empty objects

c# - 向现有的多对多关系添加附加列 - EF Code First

c# - 如何使用反射和 LINQ to Entities 来获取实体属性的值?

c# - UNET 多人游戏,让两个玩家与游戏对象交互,在主机和客户端上同步更改

c# - EF6 FluentAPI,0 :1 Unidirectional

c# - 展平复合实体