本文介绍了映射许多关系与外键参考的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于精通EF的用户来说,这应该是一个简单的问题。



我有以下架构(在我的头脑中)表格之间的关系如何。

  [FooBar] [Foo] [Bar] 

FooId PK,FK Id PK Id PK
BarId PK,FK BarId FK名称
IsRead名称描述
描述

虽然,当我尝试使用EF代码生成模式时,首先它不能解释实体之间的关系,因为我已经解释了它们(添加外键 FooId [bar] 表),并且无法完全创建 [FooBar] 桥表



如果有人可以指导我如何使用EF4代码实现上述架构,我将不胜感激。无论解决方案涉及我的POCO模型的属性,流畅的配置或两者的混合都不重要 - 只要创建所需的数据库模式。






POCO模型:

  public class Foo 
{
public int Id {get;组; }
public string Text {get;组; }
public string描述{get;组; }
public int BarId {get;组; }

public Bar Bar {get;组; } / * bar entity * /

public virtual ICollection< Bar> BridgedBars {get;组; }

public Foo()
{
Bars = new List< Bar>();
}
}

public class Bar
{
public int Id {get;组; }
public string Text {get;组; }
public string描述{get;组; }

public virtual ICollection< Foo> Fo子组; }
public virtual ICollection< Foo> BridgedFoos {get;组;

public Bar()
{
Foos = new List&Foo>();
BridgedFoos = new List< Foo>();
}
}

public class FooBar
{
public int FooId {get;组; }
public int BarId {get;组; }

public virtual Foo Foo {get;组; }
public virtual Bar Bar {get;组; }

public bool IsRead {get;组; }
}


解决方案

属于 Foo.BrideBars定义的关系 Bar 中的外键 FooId / code>。 EF不将此导航属性与 Bar 中的 ICollection< Foo> 属性之一相关联,因为有两个,EF不能唯一确定哪个是正确的对。因此,在另一端没有导航属性的 Foo.BrideBars 创建关系。可以这么说,有一个看不见的 Bar.Foo 属性导致外键。



数据库模式你想要映射到一个模型并不能真正代表多对多的关系,而是与中间的桥实体 FooBar 的两个一对多关系。您必须在导航属性中使用此类来定义正确的关系。它将如下所示:

  public class Foo 
{
public int Id {get;组; }
public string Text {get;组; }
public string描述{get;组; }

public int BarId {get;组; }
public Bar Bar {get;组; }

public virtual ICollection< FooBar> FooBars {get;组; }
}

public class Bar
{
public int Id {get;组; }
public string Text {get;组; }
public string描述{get;组; }

public virtual ICollection< Foo> Fo子组; }
public virtual ICollection< FooBar> FooBars {get;组;



public class FooBar
{
[Key,Column(Order = 0)]
public int FooId {get;组; }
[Key,Column(Order = 1)]
public int BarId {get;组; }

public virtual Foo Foo {get;组; }
public virtual Bar Bar {get;组; }

public bool IsRead {get;组; }
}

通过此模型中的命名约定将检测到正确的关系。只有 FooBar 实体,必须明确定义一个键,因为属性名称不符合约定(no Id 而没有 FooBarId 属性)。在这个模型中,使用 FooBar 中的复合键是有意义的。



我想,你真正的类和属性没有名字 Foo Bar 。如果您的真实姓名不遵循约定,您可能必须指定与注释的关系 - 或使用Fluent API:

  modelBuilder。实体< Foo>()
.HasRequired(f => f.Bar)
.WithMany(b => b.Foos)
.HasForeignKey(f => f.BarId );

modelBuilder.Entity< FooBar>()
.HasKey(fb => new {fb.FooId,fb.BarId}); //取代[Key]注释

modelBuilder.Entity< FooBar>()
.HasRequired(fb => fb.Foo)
.WithMany(f => f.FooBars)
.HasForeignKey(fb => fb.FooId);

modelBuilder.Entity< FooBar>()
.HasRequired(fb => fb.Bar)
.WithMany(b => b.FooBars)
.HasForeignKey(fb => fb.BarId);

在您的数据库模式中, FooBar 有一个复合主键:

  [FooBar] [Foo] [Bar] 

FooId PK, FK Id PK Id PK
BarId PK,FK BarId FK名称
IsRead名称描述
描述

但是,在$ code> FooBar 中有一个PK是必要的,因为EF模型中的每个实体必须具有定义的键属性 - 单个或复合 - 映射到数据库表中的主键。



在此问题中 - - 是如何处理这种类型的关系的更多细节。 (有时候,人们也称之为多对多关系有效负载( IsRead 属性是您的示例模型中的有效负载) ,但事实上它不是很多对多。)


This should be a simple question for the well versed EF user.

I have the following schema (in my head) of how the relationships between the tables should look.

[FooBar]      [Foo]          [Bar]

FooId PK,FK   Id PK          Id PK
BarId PK,FK   BarId FK       Name
IsRead        Name           Description
              Description

Though, when I try to generate the schema using EF code-first it fails to interpret the relationships between the entities as I've interpreted them (adds foreign key FooId to the [bar] table) and fails to fully create the [FooBar] bridge table.

If someone could guide me on how to achieve the above schema using EF4 code-first I'd appreciate it. Whether the solution involves attributes on my POCO models, fluent configurations or a hybrid of both doesn't matter much - as long as the desired database schema is created.


POCO Models:

public class Foo
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }
    public int BarId { get; set; }

    public Bar Bar { get; set; } /* bar entity */

    public virtual ICollection<Bar> BridgedBars { get; set; }

    public Foo()
    {
        Bars = new List<Bar>();
    }
}

public class Bar
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
    public virtual ICollection<Foo> BridgedFoos { get; set; }

    public Bar()
    {
        Foos = new List<Foo>();
        BridgedFoos = new List<Foo>();
    }
}

public class FooBar
{
    public int FooId { get; set; }
    public int BarId { get; set; }

    public virtual Foo Foo { get; set; }
    public virtual Bar Bar { get; set; }

    public bool IsRead { get; set; }
}
解决方案

Your model will indeed create a foreign key FooId in the Bar which belongs to the relationship defined by Foo.BrideBars. EF doesn't relate this navigation property to one of the ICollection<Foo> properties in Bar because there are two of them and EF cannot determine uniquely which is the correct pair. As a result it creates a relationship for Foo.BrideBars without a navigation property on the other end. So to speak, there is an invisible Bar.Foo property which causes the foreign key.

The database schema you want to map to a model does not really represent a many-to-many relationship but instead two one-to-many relationships with the intermediate "bridge" entity FooBar. You must use this class in the navigation properties to define the correct relationships. It would look like this:

public class Foo
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public int BarId { get; set; }
    public Bar Bar { get; set; }

    public virtual ICollection<FooBar> FooBars { get; set; }
}

public class Bar
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
    public virtual ICollection<FooBar> FooBars { get; set; }

}

public class FooBar
{
    [Key, Column(Order = 0)]
    public int FooId { get; set; }
    [Key, Column(Order = 1)]
    public int BarId { get; set; }

    public virtual Foo Foo { get; set; }
    public virtual Bar Bar { get; set; }

    public bool IsRead { get; set; }
}

The correct relationships will be detected by naming conventions in this model. Only for the FooBar entity it is necessary to define a key explicitly because the property names do not meet the conventions (no Id and no FooBarId property). In this model it makes sense to use a composite key in FooBar.

I guess, your real classes and properties don't have the name Foo and Bar. If your real names do not follow the conventions you possibly have to specify the relationships with annotations - or with Fluent API:

modelBuilder.Entity<Foo>()
    .HasRequired(f => f.Bar)
    .WithMany(b => b.Foos)
    .HasForeignKey(f => f.BarId);

modelBuilder.Entity<FooBar>()
    .HasKey(fb => new { fb.FooId, fb.BarId }); // replaces the [Key] annotations

modelBuilder.Entity<FooBar>()
    .HasRequired(fb => fb.Foo)
    .WithMany(f => f.FooBars)
    .HasForeignKey(fb => fb.FooId);

modelBuilder.Entity<FooBar>()
    .HasRequired(fb => fb.Bar)
    .WithMany(b => b.FooBars)
    .HasForeignKey(fb => fb.BarId);

In your database schema the FooBar table will have a composite primary key:

[FooBar]       [Foo]          [Bar]

FooId PK,FK    Id PK          Id PK
BarId PK,FK    BarId FK       Name
IsRead         Name           Description
               Description

But having a PK in FooBar is necessary because every entity in an EF model must have a key property defined - either single or composite - which maps to a primary key in the database table.

In this question - Create code first, many to many, with additional fields in association table - are more details how to work with such a type of relationship. (Sometimes people also call it "many-to-many relationship with payload" (the IsRead property is the "payload" in your example model), but in fact it's not many-to-many.)

这篇关于映射许多关系与外键参考的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 04:54