如果我了解设备可以有零个或一个车辆,反之亦然。
在旧的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