我正在尝试建立可选关系。我想我已经很接近了,但是由于某种原因,实体框架无法在我的实体上使用预定义的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 或一个人,而不是两者。
但是就我而言,并不需要在数据库级别显式实施此操作。业务逻辑可以解决这个问题。
类似地,我不在乎没有任何汽车或人的图片-我不需要它们,但是如果数据模型允许它们存在,这不是问题。业务逻辑也将弥补这一空白。
答案 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();
}
}
}
请注意,此模型确实允许汽车和人共享一张图片。