我怎样才能有一个 Foo 在 EF 5 代码中只有一个柱



我是一个胡言乱语的残骸,试图首先获取 EF 代码,让我做一些我可以在 SQL 中在 2 分钟内完成的事情。如果我还没有花 5 天时间尝试让它工作,我只会用 DDL 编写我的数据库并使用 ADO.NET。但是我离题了...

我想要 2 个表,其中 A 中的每条记录在 B 中都有一个相应的记录。它们都是同一对象的一部分;出于我不会讨论的原因,它们需要放在单独的表中(但它们确实如此,所以不要去那里(。如果我从数据库端设计它,我只会有一个从 B 到 A 的 FK 关系。

在 EF Code First 中,我尝试同时使用共享主键方法和一对一外键关联方法,但这两种方法都不适合我。我还尝试了我能想到的所有变体的 100 种左右组合,我没有进一步前进。

正如我所说,我想要的只是从 A 到 B 有一个可导航的关系(回来会很好,但我读过这是不可能的(,并且这种关系是懒惰加载的,这样我就可以说a.b并可以访问 b 的字段。

我不可能列举我尝试过的所有事情,所以让我举一个例子来说明几乎有效的方法:

class Foo
{
    public int Id { get; set; }
    public string FooProperty { get; set; }
    public virtual Bar Bar { get; set; }
}
class Bar
{
    public int Id { get; set; }
    public string BarProperty { get; set; }
}

请注意,没有从 Bar 到 Foo 的反向引用,因为 (a( SQL Server 会抱怨多个级联删除路径,(b( EF 会抱怨不知道哪一端是关联的主端。 所以... 很好 - 我可以没有它。

这让我进入数据库的是一个包含 IdFooPropertyBar_Id 字段的Foos表,以及一个包含 IdBarProperty字段的Bars表。这与我在SQL中建模的方式非常接近,尽管我可能会将FK字段放在Bar而不是Foo中。但既然是1:1,我想这并不重要。

我说这几乎有效的原因是,如果我添加一个Bar和关联的Foo,然后将它们加载回去,则Foo对象的Bar属性为 null。

using (var dbContext = new MyDbContext())
{
    var foo = dbContext.Foos.Create();
    foo.FooProperty = "Hello";
    dbContext.Foos.Add(foo);
    var bar = dbContext.Bars.Create();
    bar.BarProperty = "world";
    foo.Bar = bar;
    dbContext.SaveChanges();
}
using (var dbContext = new MyDbContext())
{
    foreach (var foo in dbContext.Foos)
        Console.WriteLine(foo.Bar.Id); // BOOM! foo.Bar is null
}

我通常希望对foo.Bar的评估会触发Bar对象的延迟加载,但事实并非如此 - 该属性仍然null

我该如何解决它?

Thsi应该可以工作:

上下文

public class FoobarCtx : DbContext
{
    public DbSet<Bar> Bars { get; set; }
    public DbSet<Foo> Foos { get; set; }
    public FoobarCtx()
    {
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Bar>()
            .HasRequired(f => f.Foo)
            .WithRequiredDependent(b => b.Bar)
            .Map(x => x.MapKey("FooId"))
            .WillCascadeOnDelete(true);
    }
}

实体

public class Foo
{
    public int Id { get; set; }
    public string Foo1 { get; set; }
    public string Foo2 { get; set; }
    public virtual Bar Bar { get; set; }
}
public class Bar
{
    public int Id { get; set; }
    public string Bar1 { get; set; }
    public string Bar2 { get; set; }
    public virtual Foo Foo { get; set; }
}

我在 EF 4.3 中对其进行了测试,但我认为它也应该在 EF5 中工作。关键是 OnModelCreate 方法。在那里,您可以将其中一个定义为主体/后代,并摆脱Microsoft SQL 限制。

有关更多信息,请参阅此博客文章。有关模型生成器(流畅 API(的更多信息,请转到此处。

要启用延迟加载,请使用 DbContext.FooSet.Create(( 方法。这里的例子。

提醒自己,如果不出意外的话......

LueTm 找到了一个解决方案,它产生了我最初想到的表结构(在 Bar 表中有一个 FooId 列(,并在两个表上产生了独立的 PK。如果不先使用 dbContext.Foos.Include(f => f.Bar) 加载 Foo.Bar 属性,仍然无法访问该属性。

我还能够很好地使用共享主键(两个表都有一个PK,但只有Foos中的表是标识(自动增量(列,并且从条形中的Id到Foos中的Id存在FK关系。

为此,我在 Foo 类中有一个 Bar 属性,在 Bar 类中有一个 Foo 属性(因此双向导航有效(,并将以下内容放在我的 OnModelCreation 中。

modelBuilder.Entity<Bar>()
                .HasRequired(x => x.Foo)
                .WithRequiredDependent(x => x.Bar)
                .WillCascadeOnDelete(true);
modelBuilder.Entity<Foo>()
                .HasRequired(x => x.Bar)
                .WithRequiredPrincipal(x => x.Foo)
                .WillCascadeOnDelete(true);

(我不确定这里的第二个调用是否真的做了什么(。

但同样,您仍然需要Include()呼叫才能访问 foo.Bar .

我自己刚刚经历了这个。我有一个 FoodEntry,有一个 Food,而 Food 有一个 FoodGroup。

public class FoodEntry
{
    public int      Id { get; set; }
    public string   User { get; set; }
    public Food     Food { get; set; }
    public decimal  PortionSize { get; set; }
    public Portion  Portion { get; set; }
    public int      Calories { get; set; }
    public Meal  Meal { get; set; }
    public DateTime? TimeAte { get; set; }
    public DateTime EntryDate { get; set; }
}
public class Food
{
    public int       Id { get; set; }
    public string    Name { get; set; }
    public FoodGroup FoodGroup { get; set; }
}
public class FoodGroup
{
    public int Id { get; set; }
    public string Name { get; set; }
}

我首先使用代码,我的 POCO 类的定义就像你的一样。我没有标记为虚拟的属性。

无论如何,数据库都会如我所期望的那样生成 - 使用您所描述的外键。

但是此查询导致仅获取在 Food、Part 和 Meal 属性中包含空值的 FoodEntry 集合:

var foodEntries = db.FoodEntries
            .Where(e => e.User == User.Identity.Name).ToList();

我将查询更改为此,并为我的集合加载了整个图形:

var foodEntries = db.FoodEntries
            .Include( p => p.Food)
            .Include(p => p.Food.FoodGroup)
            .Include(p => p.Portion)
            .Include( p => p.Meal)
            .Where(e => e.User == User.Identity.Name).ToList()
            ;

对于 1:1 关系和 1:多关系(Foo 有几个柱线和一个 CurrentBar (:

        modelBuilder.Entity<Foo>()
            .HasOptional(f => f.CurrentBar)
            .WithMany()
            .HasForeignKey(f => f.CurrentBarId);
        modelBuilder.Entity<Bar>()
            .HasRequired(b => b.Foo)
            .WithMany(f => f.Bars)
            .HasForeignKey(b => b.FooId);

相关内容

最新更新