我有实体A和B,我想在A和B之间创建2个不同的1-1关联.A应该扮演校长的角色。像这样:
public class A
{
public int Id {get; set;}
public B B1 {get; set;}
public B B2 {get; set;}
}
public class B
{
public int Id {get; set;}
}
由于EF不支持一对一的外键关联,因此无法使用EF创建工作模型/数据库。对我来说这听起来像是一个严重的限制。是否有计划在即将推出的EF版本中支持此类协会?
使这项工作成功的最佳解决方法是什么?我知道创建两个一对多的关联。但是,这会使B成为主体,并且会给我带来级联删除的问题。
感谢您回复我的问题。下面是我想要做的一个例子,即在实体A和另一个实体B之间创建两个(或更多)1对1关联。这是EF可以在vNext中支持的东西,否则,为什么会这样是个坏主意?
再次感谢, Merijn
public class A
{
public int Id {get; set;}
public int B1_Id {get; set;}
public B B1 {get; set;}
public int B2_Id {get; set;}
public B B2 {get; set;}
}
public class B
{
public int Id {get; set;}
}
public class SampleContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<A>().HasKey(c => c.Id);
modelBuilder.Entity<B>().HasKey(c => c.Id);
modelBuilder.Entity<A>().HasRequired(c => c.B1).WihOptional().ForeignKey(x=>x.B1_Id);
modelBuilder.Entity<A>().HasRequired(c => c.B2).WihOptional().ForeignKey(x=>x.B2_Id);
}
}
答案 0 :(得分:4)
如果“v-Next”是实体框架6,那么不,它显然不会支持一对一的外键关联,因为您可以看到on the roadmap for all features planned for EF 6。
您还可以在路线图和still marked as "Under Review" on UserVoice上看到唯一约束支持。
因为一对一的外键关联基本上是与外键列上的唯一约束的一对多关联,所以我希望在Unique Constraint之前不会实现一对一的FK关联支持是可用的。如果您希望A
是两个关系中的主体,则尤其需要它。目前,EF不支持主体密钥不是主键但某些列具有唯一约束的关系。
In this blog post该功能被描述并提及它被“推迟”,所以让我们希望EF 7。
答案 1 :(得分:1)
也许这是一个术语问题。 在Code first EF中,EF不允许您与Principal和Dependent之间具有1:1的关系,并且彼此具有外键 或者具有与Principal无关的自己的主键。 在您的示例中,它看起来像是需要2个导航属性的情况。 严格来说,它不是1:1。因为你有两个关系到同一个表。 你有2种类型1的关系:1。EF认为这个数量为1。
如果你有一个真正的1:1关系,EF会希望依赖者拥有与主要关键词相同的主键 您可以在Both Principle和dependent上定义Multiple NAVIGATION属性,这会导致索引。
因此,您可能希望调查多对一配置 如果希望主节点在数据库级别具有OPTINAL外键,则需要稍后在迁移期间或使用脚本添加此FK。 但可以说,这最好被视为业务逻辑/规则检查,而不是主要的可选FK。 所以是的,在确切地匹配数据库上的可能性方面存在限制 但是在代码优先方案中实际上是必要的。
这里的巧妙之处btw就是在数据库中建模你想要的Code。 使用EF Powertool nuget从DB工程中设计Codefirst。
EG mini DB,只有所需的表关系。 在解决方案中创建一个新项目。安装实体框架Powertools。 然后在新项目中使用右键单击选项“首先从DB反向工程代码”。
它显示了如何在代码中构建它,如果它可以....: - )
我认为您想要实现的目标...请参阅代码示例(对不起,如果我误解了您的观点)代码应该在NUGET加载时执行
using System.Data.Entity;
namespace EF_DEMO
{
class FK121
{
public static void ENTRYfk121(string[] args)
{
var ctx = new Context121();
ctx.Database.Create();
System.Console.ReadKey();
}
}
public class Main
{
public int MainId { get; set; }
public string BlaMain { set; get; }
public int? Sub1Id { set; get; } // Must be nullable since we want to use EF foreign key
public int? Sub2Id { set; get; } // Must be nullable since we want to use EF foreign key
public virtual Sub Sub1 { get; set; } // Reverse navigation
public virtual Sub Sub2 { get; set; } // Reverse navigation
// you may also need
public virtual ICollection<Sub> Subs { get; set; }
}
public class Sub
{
public int SubId { get; set; } // Deliberately DIFFERENT KEY TO MAIN.... not 1:1 so this is possible
public string blasub { set; get; }
public int MainId { set; get; } //set in API , this the FK
public virtual Main Main { get; set; } // van to Principal
}
public class Context121 : DbContext
{
static Context121()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context121>());
}
public Context121()
: base("Name=Demo") { } // webconfig required to match
public DbSet<Main> Mains { get; set; }
public DbSet<Sub> Subs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Main>().HasKey(t => t.MainId)
.HasOptional(t => t.Sub1)
.WithMany()
.HasForeignKey(t=>t.Sub1Id) ; // tell EF the field is in POCO, use this please, otherwise it will create it.
modelBuilder.Entity<Main>()
.HasOptional(t => t.Sub2).WithMany()
.HasForeignKey(t=>t.Sub2Id);
modelBuilder.Entity<Sub>()
.HasKey(t => t.SubId)
.HasRequired(q => q.Main)
.WithMany()
.HasForeignKey(t => t.MainId);
}
}
}
... WEBCONFIG
<connectionStrings>
<add name="Demo" connectionString="Data Source=localhost;Initial Catalog=Demo;Integrated Security=True;MultipleActiveResultSets=True;App=EntityFramework"
providerName="System.Data.SqlClient" />
</connectionStrings>
答案 2 :(得分:0)
解释你需要解决什么问题?这是EF 5.0中一对一映射的示例
class Program
{
static void Main(string[] args)
{
using (var context = new SampleContext())
{
var mainEntity = new MainEntity();
mainEntity.DetailEntity = new DetailEntity();
context.SaveChanges();
}
}
}
public class SampleContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MainEntity>().HasKey(c => c.Id);
modelBuilder.Entity<DetailEntity>().HasKey(c => c.Id);
modelBuilder.Entity<MainEntity>().HasOptional(c => c.DetailEntity).WithRequired(p => p.MainEntity);
modelBuilder.Entity<DetailEntity>().HasRequired(c => c.MainEntity).WithOptional(p => p.DetailEntity);
}
public virtual DbSet<MainEntity> MainEntities { get; set; }
public virtual DbSet<DetailEntity> DetailEntities { get; set; }
}
public class MainEntity
{
public int Id { get; set; }
public DetailEntity DetailEntity { get; set; }
}
public class DetailEntity
{
public int Id { get; set; }
public MainEntity MainEntity { get; set; }
}