代码之家  ›  专栏  ›  技术社区  ›  Flater

ef code first可选到具有单个FK列的可选

  •  0
  • Flater  · 技术社区  · 6 年前

    我正试图建立一种从选择性到选择性的关系。我认为我已经非常接近了,但是由于某种原因,实体框架无法在我的实体上使用预定义的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没有fk to foo。

    以及Fluent API:

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

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

    其他一切都如我所料, Bar 表没有FK字段到 Foo .

    在网上查找时,我发现了一个建议,可以执行以下操作:

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

    但是,除非我移除 BarId 从我的 上课,我不想那样做。我特别想保留 巴里德 所以我可以在需要的时候使用它来创建/破坏关系。

    如何让ef使用我创建的fk属性,而不是生成一个额外的列并使用它?

    旁注:我不想使用数据注释。整个解决方案是围绕将实体(域项目)与数据提供程序(数据库EF项目)分离而构建的。我们只使用Fluent API来设置所有这些。


    为了完整起见,目的是 酒吧 可以有多个这样的关系:

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

    这就是为什么我不想让FK出现在酒吧里的原因:你最终会为每个人都写一个专栏,我们知道一个酒吧只有一个关系。


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

    = Person
    酒吧 = Picture
    ADifferentFoo = Car

    一个人可以选择有一张照片。汽车可以有选择地有一张图片。

    图片总是属于任何一辆车 异或 一个人,不可能两者兼而有之。
    但就我所关心的,这不需要在数据库级别上显式地强制执行。业务逻辑可以处理这个问题。

    同样,我不在乎没有车或人的照片-我不需要它们,但如果数据模型允许它们存在,这不是问题。业务逻辑也将覆盖这个缺口。

    1 回复  |  直到 6 年前
        1
  •  0
  •   David Browne - Microsoft    6 年前

    就这样吧:

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

    ?

    您打算如何使用图片表中的FK来实施它?

    您可以使用检查约束

    这都是假设EF6,这些是一对多的关系。

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

    ef core有一个关于备用键的一流概念,不仅可以使用指向备用键的fk,还可以使用 实现1对1关系的备用键。如

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

    请注意,这个模型允许一辆车和一个人共享一张图片。