EF代码首先是可选的,还是带有单个FK列的可选

时间:2018-07-17 14:13:44

标签: entity-framework ef-code-first

我正在尝试建立可选关系。我想我已经很接近了,但是由于某种原因,实体框架无法在我的实体上使用预定义的FK属性。

public class Foo
{
    public Guid? BarId { get; set; }
    public virtual Bar Bar { get; set; }
}

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

这正是我想在数据库中看到的内容。 Foo有FK列,但Bar没有Foo到Foo。

和Fluent API:

modelBuilder
    .Entity<Foo>()
    .HasOptional(f => f.Bar)
    .WithOptionalDependent(b => b.Foo);

但是,当我生成数据库时,EF将FooId属性设置为简单的标量属性,并创建了自己的Foo_Id用于FK。

其他一切与我期望的一样,Bar表没有Foo的FK字段。

在网上,我发现了以下建议:

modelBuilder
    .Entity<Foo>()
    .HasOptional(f => f.Bar)
    .WithOptionalDependent(b => b.Foo)
    .Map(d => d.MapKey("BarId"));

但是,除非我从BarId类中删除Foo,否则这是行不通的,而且我也不想这样做。我特别想保留BarId,以便在需要时可以使用它创建/销毁关系。

如何让EF使用我创建的FK属性,而不是生成额外的列并使用它?

侧面注释:我不想使用数据注释。整个解决方案是围绕将实体(域项目)与数据提供者(数据库EF项目)分开来构建的。我们仅使用Fluent API进行设置。


出于完整性考虑,目的是Bar可以具有以下多个关系:

public class ADifferentFoo
{
    public Guid? BarId { get; set; }
    public virtual Bar Bar { get; set; }
}

这就是为什么我不想在Bar中拥有FK:您最终每个人都有一列,而且我们知道Bar只会每个都有一个关系。


也许一个具体的例子有帮助:

Foo = Person
Bar = Picture
ADifferentFoo = Car

一个人可以选择拥有一张图片。汽车可以选择具有图片。

图片总是属于汽车 XOR 或一个人,而不是两者。
但是就我而言,并不需要在数据库级别显式实施此操作。业务逻辑可以解决这个问题。

类似地,我不在乎没有任何汽车或人的图片-我不需要它们,但是如果数据模型允许它们存在,这不是问题。业务逻辑也将弥补这一空白。

1 个答案:

答案 0 :(得分:0)

怎么样:

public class Person
{
    public int PersonID { get; set; }
    public int PictureId { get; set; }
    public virtual Picture Picture { get; set; }

}
public class Car
{
    public int CarId { get; set; }
    public int PictureId { get; set; }
    public virtual Picture Picture { get; set; }
}

public class Picture
{
    public int PictureId { get; set; }
}

  

您如何建议通过Picture表中的FK强制实施?

您可以使用“检查约束”

所有这些都假定为EF 6,并且它们是一对多关系。

对于1-1,FK必须是一个键,而EF 6不支持多个键。

EF Core具有备用键的一流概念,不仅您可以使用指向备用键的FK,还可以使用备用键的FK来实现备用键。一对一关系。 EG

using Microsoft.EntityFrameworkCore;
using System.Linq;
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;

namespace efCoreTest
{

    public class Person
    {
        public int PersonID { get; set; }
        public int? PictureId { get; set; }
        public virtual Picture Picture { get; set; }

    }
    public class Car
    {
        public int CarId { get; set; }
        public int? PictureId { get; set; }
        public virtual Picture Picture { get; set; }
    }

    public class Picture
    {
        public int PictureId { get; set; }
        public virtual Car Car { get; set; }

        public virtual Person Person { get; set; }
    }


    public partial class Db : DbContext
    {
        public DbSet<Car> Cars { get; set; }
        public DbSet<Picture> Pictures { get; set; }

        public DbSet<Person> Persons { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Car>().HasAlternateKey(c => c.PictureId);
            modelBuilder.Entity<Person>().HasAlternateKey(c => c.PictureId);

            modelBuilder.Entity<Car>().HasOne(c => c.Picture).WithOne(p => p.Car);
            modelBuilder.Entity<Person>().HasOne(c => c.Picture).WithOne(p => p.Person);
            base.OnModelCreating(modelBuilder);
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=localhost;database=efcore2test;integrated security=true");
            base.OnConfiguring(optionsBuilder);
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            using (var db = new Db())
            {


                db.Database.EnsureDeleted();
                db.Database.EnsureCreated();

                var c = new Car();
                var p = new Person();

                var pic = new Picture();
                pic.Car = c;
                pic.Person = p;

                db.Add(c);
                db.Add(p);
                db.Add(pic);

                db.SaveChanges();


            }

            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();
        }
    }
}

请注意,此模型确实允许汽车和人共享一张图片。