如果我瞭解設備可以有零個或一個車輛,反之亦然。
在舊的DB模型中,兩個表(設備或車輛)中的一個應該有一個引用另一個表的可爲空的字段。
要在EF中配置它,您必須使用數據註釋或流暢的界面。 這裏的模型和上下文的代碼
public class ClassA
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ClassB ClassB { get; set; }
}
public class ClassB
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ClassA ClassA { get; set; }
}
class Context : DbContext
{
public Context(DbConnection connection)
: base(connection, false)
{ }
public DbSet<ClassA> As { get; set; }
public DbSet<ClassB> Bs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ClassB>().HasOptional(c => c.ClassA).WithOptionalDependent(c => c.ClassB);
}
}
正如你所想象,有使用該模型的一些限制。即模型(POCO模型)允許您擁有一個classA1,引用一個引用classA2的classB1(類型相同但classA1不同的實例)。 DB和EF沒有。這裏用一個查詢爲例傾倒在EF如何在這種情況下,(我覺得很有意思!)
using (Context context = new Context(connection))
{
ClassA classA;
ClassB classB;
// Very simple behaviour (as expected). You can see the queries after SaveChanges()
classA = new ClassA {Description = "B empty"};
context.As.Add(classA);
classA = new ClassA { Description = "B full", ClassB = new ClassB(){Description = "ClassB full"}};
context.As.Add(classA);
classB = new ClassB { Description = "B empty"};
context.Bs.Add(classB);
context.SaveChanges();
/*
insert into [ClassAs]([Description])
values (@p0);
@p0 = B full
insert into [ClassAs]([Description])
values (@p0);
@p0 = B empty
insert into [ClassBs]([Description], [ClassA_Id])
values (@p0, @p1);
@p0 = ClassB full
@p1 = 1
insert into [ClassBs]([Description], [ClassA_Id])
values (@p0, null);
@p0 = B empty
*/
// Here a new classB references an already referenced classA. But we don't want this!!!
// EF works like we want, the classA is detached from the old classB then attached to the
// new classB. Below you can see the queries
classB = new ClassB { Description = "B full with the wrong A", ClassA = classA};
context.Bs.Add(classB);
/*
update [ClassBs]
set [ClassA_Id] = null
where (([Id] = @p0) and ([ClassA_Id] = @p1))
@p0 = 1
@p1 = 1
insert into [ClassBs]([Description], [ClassA_Id])
values (@p0, @p1);
@p0 = B full with the wrong A
@p1 = 1
*/
context.SaveChanges();
}
現在,最後一步...... 望着數據庫的結構這POCO模型
ClassBs(Id, Description, ClassA_Id : ClassAs)
ClassAs(Id, Description)
在數據庫模型中,我們可以有2個不同的具有相同ClassA實例的ClassB實例(EF不允許我們這樣做,但我們可以從SQL實現)。 使用SQL黑客後,你可以運行這個測試
using (Context context = new Context(connection))
{
foreach (var classB in context.Bs.ToList())
{
if (classB.ClassA == null)
continue;
Console.WriteLine("{0} {1} {2}", classB.Id, classB.ClassA.Id, classB.ClassA.ClassB.Id);
}
}
這個測試會引發異常
===
「System.InvalidOperationException」類型的未處理的異常出現在EntityFramework.dll
附加信息:發生關係多重性約束衝突:EntityReference中只能有一個相關對象,但該查詢返回多個相關對象。這是一個不可恢復的錯誤。
===
我們可以避免來自SQL的人做到了嗎?是的,在ClassA_Id字段上插入一個唯一約束。
非常感謝您的驗證。所以在這種情況下,如果不使用流利的API,就無法解決問題了? (我問這個問題的唯一原因是因爲我喜歡嘗試將類中的所有內容都保存爲屬性,因爲我個人覺得它很容易閱讀並遵循:)) –
其實我認爲不可能。 – bubi