ServiceStack Ormlite:parent 和 child 表之间的循环引用阻止创建外键
ServiceStack Ormlite: Circular reference between parent and child tables prevents foreign key creation
我们正在试验从 EF6 到 ServiceStack.OrmLite 的转换,并且在 table 创建期间遇到问题 Parent table 包含对 a 的引用(default/active)Childtable。我们有一个 1:many Parent:Child 关系,其中 Parent 有一个对特定 child 的附加可选引用。生成的数据库 table 将各自包含彼此的外键,例如
Parent table:
Id (int) | Name (varchar) | ActiveChildId (int null FK)
Child table:
Id (int) | Description (varchar) | ParentId (int FK)
我们正在尝试模仿 EF 提供的导航 属性 功能,但不确定这是否可行?
例如,如果我们声明如下类,其中
public class Parent
{
public int Id {get;set;}
public string Name {get;set;}
// the item currently published, modelled like an EF navigation property
[Reference]
public Child ActiveChild {get;set;}
[References(typeof(Child))]
public int? ActiveChildId { get; set; }
// all items mapped to this Parent
[Reference]
public List<Child> AllChildren {get;set;}
}
public class Child
{
public int Id {get;set;}
public string Description {get;set;}
[References(typeof(Parent))]
public int ParentId {get;set;}
[Reference]
public Parent MyParent {get;set;}
}
现在,当我们使用Ormlite table创作时,如:
using (var db = DbFactory.Open())
{
db.CreateTableIfNotExists<Parent>();
db.CreateTableIfNotExists<Child>();
}
我们收到如下错误:
System.Data.SqlClient.SqlException (0x80131904): Foreign key 'FK_Parent_Child_ActiveChildId' references invalid table 'Child'.
Could not create constraint or index. See previous errors.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
[etc etc]
基本上,似乎创建 Parent table 失败了,因为 Child table 尚不存在,因此无法创建外键,类似地反转table 创建顺序失败,因为没有 Parent 就无法创建 Child?
我们是否能够在 OrmLite 中以这种方式对我们的 类 进行建模,或者如果不能,那么捕获这种关系的 suggested/recommended 结构是什么?
谢谢
OrmLite 是代码优先的 ORM,它的 POCO 是底层 table 的 1:1 映射。您不能在 OrmLite 中定义这样的循环关系,因为您不能在 SQL 中定义这样的循环关系,而不求助于多步骤 table 创建,其中毕竟添加了外键约束 table 已创建。我建议不要使用循环外键定义 tables,您可以随时在创建 tables 之后添加它们。
使用 [References(Type)]
属性创建一个外键,但这对于 OrmLite POCO References 不是必需的,它可以使用隐式命名约定来定义隐式关系,例如:
public class Parent
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[Reference]
public Child ActiveChild { get; set; }
public int? ActiveChildId { get; set; }
[Reference]
public List<Child> AllChildren { get; set; }
}
public class Child
{
[AutoIncrement]
public int Id { get; set; }
public int ParentId { get; set; }
public string Description { get; set; }
}
然后您可以正常创建和使用:
db.DropAndCreateTable<Parent>();
db.DropAndCreateTable<Child>();
var parent = new Parent
{
Name = "Parent",
ActiveChild = new Child { Description = "Active" },
AllChildren = new List<Child>
{
new Child { Description = "Child 1" },
new Child { Description = "Child 2" },
}
};
db.Save(parent, references:true);
var dbParent = db.LoadSelect<Parent>();
dbParent.PrintDump();
我们正在试验从 EF6 到 ServiceStack.OrmLite 的转换,并且在 table 创建期间遇到问题 Parent table 包含对 a 的引用(default/active)Childtable。我们有一个 1:many Parent:Child 关系,其中 Parent 有一个对特定 child 的附加可选引用。生成的数据库 table 将各自包含彼此的外键,例如
Parent table:
Id (int) | Name (varchar) | ActiveChildId (int null FK)
Child table:
Id (int) | Description (varchar) | ParentId (int FK)
我们正在尝试模仿 EF 提供的导航 属性 功能,但不确定这是否可行?
例如,如果我们声明如下类,其中
public class Parent
{
public int Id {get;set;}
public string Name {get;set;}
// the item currently published, modelled like an EF navigation property
[Reference]
public Child ActiveChild {get;set;}
[References(typeof(Child))]
public int? ActiveChildId { get; set; }
// all items mapped to this Parent
[Reference]
public List<Child> AllChildren {get;set;}
}
public class Child
{
public int Id {get;set;}
public string Description {get;set;}
[References(typeof(Parent))]
public int ParentId {get;set;}
[Reference]
public Parent MyParent {get;set;}
}
现在,当我们使用Ormlite table创作时,如:
using (var db = DbFactory.Open())
{
db.CreateTableIfNotExists<Parent>();
db.CreateTableIfNotExists<Child>();
}
我们收到如下错误:
System.Data.SqlClient.SqlException (0x80131904): Foreign key 'FK_Parent_Child_ActiveChildId' references invalid table 'Child'.
Could not create constraint or index. See previous errors.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
[etc etc]
基本上,似乎创建 Parent table 失败了,因为 Child table 尚不存在,因此无法创建外键,类似地反转table 创建顺序失败,因为没有 Parent 就无法创建 Child?
我们是否能够在 OrmLite 中以这种方式对我们的 类 进行建模,或者如果不能,那么捕获这种关系的 suggested/recommended 结构是什么?
谢谢
OrmLite 是代码优先的 ORM,它的 POCO 是底层 table 的 1:1 映射。您不能在 OrmLite 中定义这样的循环关系,因为您不能在 SQL 中定义这样的循环关系,而不求助于多步骤 table 创建,其中毕竟添加了外键约束 table 已创建。我建议不要使用循环外键定义 tables,您可以随时在创建 tables 之后添加它们。
使用 [References(Type)]
属性创建一个外键,但这对于 OrmLite POCO References 不是必需的,它可以使用隐式命名约定来定义隐式关系,例如:
public class Parent
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[Reference]
public Child ActiveChild { get; set; }
public int? ActiveChildId { get; set; }
[Reference]
public List<Child> AllChildren { get; set; }
}
public class Child
{
[AutoIncrement]
public int Id { get; set; }
public int ParentId { get; set; }
public string Description { get; set; }
}
然后您可以正常创建和使用:
db.DropAndCreateTable<Parent>();
db.DropAndCreateTable<Child>();
var parent = new Parent
{
Name = "Parent",
ActiveChild = new Child { Description = "Active" },
AllChildren = new List<Child>
{
new Child { Description = "Child 1" },
new Child { Description = "Child 2" },
}
};
db.Save(parent, references:true);
var dbParent = db.LoadSelect<Parent>();
dbParent.PrintDump();