Entity Framework 5.0 zusammengesetzter Fremdschlüssel zu Nicht-Primärschlüssel - ist das möglich?
Ich verwende Entity Framework 5.0.0.0 in einer .net 4.5-Konsolenanwendung und muss auf eine Datenbank mit zwei Tabellen zugreifen, zwischen denen eine Fremdschlüsselbeziehung besteht.
Das Seltsame daran ist, dass der Fremdschlüssel dazwischen liegtB(Almost1, Almost2)
undA(Almost1, Almost2)
nicht vonB(AId)
zuA(AId)
. Dies ist vom SQL Server als erlaubtAlmost1
undAlmost2
kombiniert sind einzigartig und keine sind nullable (auf TabelleA
Zumindest - aufB
Sie sind wie es ist eine optionale Beziehung, aber das ist von by).
Hier einige SQL-Anweisungen zum Erstellen dieser Situation:
CREATE TABLE [dbo].[A](
[AId] [int] IDENTITY(1,1) NOT NULL,
[Almost1] [int] NOT NULL,
[Almost2] [int] NOT NULL,
CONSTRAINT [PK_A] PRIMARY KEY CLUSTERED
(
[AId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [A_Constraint] UNIQUE NONCLUSTERED
(
[Almost1] ASC,
[Almost2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[B](
[BId] [int] IDENTITY(1,1) NOT NULL,
[Almost1] [int] NULL,
[Almost2] [int] NULL,
CONSTRAINT [PK_B] PRIMARY KEY CLUSTERED
(
[BId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[B] ADD CONSTRAINT [FK_A_B] FOREIGN KEY([Almost1], [Almost2])
REFERENCES [dbo].[A] ([Almost1], [Almost2])
Die Sache ist, es scheint, dass es von Entity Framework nicht erlaubt ist - ist dies der Fall oder definiere ich mein Modell einfach nicht richtig?
Hier ist meine c #:
public class MyContext : DbContext
{
public MyContext(string connectionString) : base(connectionString)
{
MyAs = Set<A>();
MyBs = Set<B>();
}
public DbSet<A> MyAs { get; private set; }
public DbSet<B> MyBs { get; private set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var aEntity = modelBuilder.Entity<A>();
aEntity.ToTable("A");
aEntity.HasKey(a => a.AId);
var bEntity = modelBuilder.Entity<B>();
bEntity.ToTable("B");
bEntity.HasKey(a => a.BId);
bEntity
.HasOptional(b => b.A)
.WithMany(a => a.Bs)
.Map(m => m.MapKey("Almost1", "Almost2"));
}
}
public class A
{
public int AId { get; set; }
public int Almost1 { get; set; }
public int Almost2 { get; set; }
public virtual ICollection<B> Bs { get; private set; }
public void AddB(B b)
{
if (b == null) throw new ArgumentNullException("b");
if (Bs == null) Bs = new List<B>();
if (!Bs.Contains(b)) Bs.Add(b);
b.A = this;
}
}
public class B
{
public int BId { get; set; }
public virtual A A { get; set; }
}
class Program
{
static void Main()
{
using (var ctx = new MyContext(@"connection string"))
{
ctx.MyAs.Add(new A { Almost1 = 1, Almost2 = 1 });
ctx.SaveChanges();
}
}
}
Es wirft einInvalidOperationException
Sprichwort:
Die angegebenen Assoziations-Fremdschlüsselspalten 'Almost1, Almost2' sind ungültig. Die Anzahl der angegebenen Spalten muss mit der Anzahl der Primärschlüsselspalten übereinstimmen.
Wenn ich das ignoriereAId
Spalte und stattdessen machenAlmost1
undAlmost2
ein zusammengesetzter Primärschlüssel, also meineOnModelCreating
Methode sieht jetzt so aus:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var aEntity = modelBuilder.Entity<A>();
aEntity.ToTable("A");
aEntity.HasKey(a => new { a.Almost1, a.Almost2 });
aEntity.Ignore(a => a.AId);
var bEntity = modelBuilder.Entity<B>();
bEntity.ToTable("B");
bEntity.HasKey(a => a.BId);
bEntity
.HasOptional(b => b.A)
.WithMany(a => a.Bs)
.Map(m => m.MapKey("Almost1", "Almost2"));
}
Es funktioniert, aber ich möchte das nicht wirklich tun, da es auch einen Tisch gibt (nennen wir esC
) das bezieht sich aufA
auf die traditionelle Art und Weise mit einemAId
Spalte und der Fremdschlüssel geht abC.AId
zuA.AId
.
Ja, es ist ein bisschen seltsam, wie ich weiß - aber ist es möglich, in Entity Framework damit umzugehen?