C# 使用实体为多个表配置一无一关系

C# 使用实体为多个表配置一无一关系,c#,entity-framework,C#,Entity Framework,我所处的情况是,一个表有两个一无/一关系。如何首先使用实体框架代码实现此功能 我看到了以下链接 从本质上讲,依赖端需要有一个与主端相同的主键。但我厌倦了在没有确认和正确了解发生了什么的情况下,用不止一个一无/一的关系来实现这一点。此外,我不知道如何构造语句,因为它没有常规的外键 我也看到了那些让我无法辨认的东西 有关my DB图表的相关部分,请参见下文: 因此本质上,一个播放器不应该在没有DKImage的情况下保存,同样地,产品也不应该在没有DKImage的情况下保存 下面是模型的代码

我所处的情况是,一个表有两个一无/一关系。如何首先使用实体框架代码实现此功能

我看到了以下链接

从本质上讲,依赖端需要有一个与主端相同的主键。但我厌倦了在没有确认和正确了解发生了什么的情况下,用不止一个一无/一的关系来实现这一点。此外,我不知道如何构造语句,因为它没有常规的外键

我也看到了那些让我无法辨认的东西

有关my DB图表的相关部分,请参见下文: 因此本质上,一个
播放器
不应该在没有
DKImage
的情况下保存,同样地,
产品
也不应该在没有
DKImage
的情况下保存

下面是模型的代码:
播放器
产品
DKImages
(我知道这不正确,我只是这样实现的,以便生成数据库并显示图表)

玩家 产品 编辑


我被告知上面的代码是正确的。如果是这样,那么如何使用上述代码创建CRUD LINQ语句(或任何构造CRUD语句的方法)。

您的播放器表中的示例如下:

public class Player
{

    // All the rest you already coded

    [Required]
    public int ImageID

    [ForeignKey("ImageID")]
    public virtual DKImage DKImage {get;set;}
}
这将迫使玩家拥有DK形象,但正如评论中所说,这将创建一对多关系

另一种解决方法是将所有玩家字段放入DKImage表中,如果没有与此DKImage关联的玩家,则这些字段将为空

编辑1到1..0

Ivan Stoev的链接获得了一些关于如何实现这一点的有趣见解:

似乎您必须在类中添加更多的代码:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<DKImage>().HasOptional(t => t.Player).WithRequired();

}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity();
}
如果本教程是正确的,则内容如下:

“DKImage实体具有与一个玩家对象的可选关联,但该关联是玩家实体所必需的”


我还没有测试过它。

您在这里想要的是:多个实体具有一种类型的子实体。它们通常用于注释、备注、文件等,通常应用于1:n关联。在您的案例中,存在多态性1:1关联。基本上,这些关联如下所示(使用更通用的名称):

如何实施

实体框架6 在EF6中,这就是问题所在。EF6将1:1关联实现为共享主键:子项的主键也是其父项主键的外键。这意味着
Image.ID
上应该有两个FK,一个指向
Person.ID
,另一个指向
Product.ID
。从技术上说,这不是问题,从语义上说,这是问题。两个父实体现在拥有相同的图像,或者,以不同的方式表示,一个图像应该始终属于两个不同的父实体。在现实生活中,这是胡说八道

解决方案可以是反向引用:

但现在还有另一个问题。引用的实体称为主体,另一个实体是从属的。在第二个图中,
图像
是主体,因此为了创建
人物
,必须先插入其图像,然后该人物复制其主键。这是违反直觉的,很可能也是不切实际的。如果图像是可选的,这是不可能的

尽管如此,因为在您的情况下,您希望图像是必需的,所以让我展示一下这个关联在EF6中是如何映射的

让我们以这个简单的模型为例:

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual Image Image { get; set; }
}

public class Product
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual Image Image { get; set; }
}

public class Image
{
    public int ImgID { get; set; } // Named for distinction
    public string Url { get; set; }
}
所需的映射是:

modelBuilder.Entity<Image>().HasKey(pd => pd.ImgID);
modelBuilder.Entity<Person>().HasRequired(p => p.Image).WithRequiredDependent();
modelBuilder.Entity<Product>().HasRequired(p => p.Image).WithRequiredDependent();
以及映射:

modelBuilder.Entity<Person>().Property(p => p.ID).UseSqlServerIdentityColumn();
modelBuilder.Entity<Person>()
    .HasOne(p => p.Image)
    .WithOne()
    .HasForeignKey<Image>(p => p.PersonID);
modelBuilder.Entity<Product>().Property(p => p.ID).UseSqlServerIdentityColumn();
modelBuilder.Entity<Product>()
    .HasOne(p => p.Image)
    .WithOne()
    .HasForeignKey<Image>(p => p.ProductID);
modelBuilder.Entity<Image>().HasKey(p => p.ImgID);

这将在数据库端将关联转换为真正的1:1关联。如果没有唯一索引,从数据库的角度来看,它将是一个1:n的关联。

您有什么担心?播放器和产品是分开的表。只是他们不会有自己的(身份)PK,但会使用DKImages PK的子集。问题是什么?你是在问你在这一点上做得好吗?好。。。的确这是正确的方法。如果您对此代码有问题,请在问题中说明。如果没有问题,请删除您的问题并继续努力。@AntoinePelletier这是正确的??如何将图像与要添加到数据库的播放器/产品关联?我认为这是错误的,因为没有外键,我可以将图像与玩家/产品关联。@IvanStoev你能用某种隐喻详细说明你的答案吗?我真的不明白,看看。希望作者能比我解释得更好:)我的观点是,我认为一个表的PK同时是另一个表的FK没有问题。请注意,这会创建一对多关系(
DKImage
10..N
Player
),而要求是10。。1@IvanStoev是的,我刚刚测试了代码,我已取消标记为答案,因此如果您希望DKImage的玩家不超过一名。。。我会把玩家表的字段放到DKImage表中,如果没有关联的玩家,它们将为空。但您的问题仍然非常有趣,是否有可能在实体框架中建立1到1..0的关系?我开始怀疑了。@James9oo0我已经更新了我的答案,如果这不是解决方案,告诉我,我希望你不会介意有一天我对你的问题悬赏?@AntoinePelletier我不知道悬赏是什么,但去吧!我还没有时间测试代码,但我会尽快通知您。现在我想使用EF Core,它提供的解决方案似乎更健壮。您所说的解决方案是最可行的:“每个实体都有单独的图像表。”
public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual Image Image { get; set; }
}

public class Product
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual Image Image { get; set; }
}

public class Image
{
    public int ImgID { get; set; } // Named for distinction
    public string Url { get; set; }
}
modelBuilder.Entity<Image>().HasKey(pd => pd.ImgID);
modelBuilder.Entity<Person>().HasRequired(p => p.Image).WithRequiredDependent();
modelBuilder.Entity<Product>().HasRequired(p => p.Image).WithRequiredDependent();
public class Image
{
    public Image()
    { }
    public int ImgID { get; set; }
    public int? PersonID { get; set; }
    public int? ProductID { get; set; }
    public string Url { get; set; }
}
modelBuilder.Entity<Person>().Property(p => p.ID).UseSqlServerIdentityColumn();
modelBuilder.Entity<Person>()
    .HasOne(p => p.Image)
    .WithOne()
    .HasForeignKey<Image>(p => p.PersonID);
modelBuilder.Entity<Product>().Property(p => p.ID).UseSqlServerIdentityColumn();
modelBuilder.Entity<Product>()
    .HasOne(p => p.Image)
    .WithOne()
    .HasForeignKey<Image>(p => p.ProductID);
modelBuilder.Entity<Image>().HasKey(p => p.ImgID);