我正在使用Shaolinq库进行数据库使用,并且一对一关系存在问题。我有以下数据库架构:
create table A (
Id INT NOT NULL,
PRIMARY KEY (`Id`)
);
create table B (
Id INT NOT NULL,
PRIMARY KEY (`Id`),
CONSTRAINT `fk_a_b_id` FOREIGN KEY (`Id`) REFERENCES `A` (`Id`)
);
基本上,这两个表包含有关相同内容的信息,只是包含不同的数据。那是有人设计的方式,我无法更改。
但是,在代码中,我希望将所有这些数据放在一个对象中。我一直在尝试BackReference,但没有运气:
[DataAccessObject]
public abstract class A : DataAccessObject<uint>
{
[AutoIncrement]
[PersistedMember]
public abstract uint Id { get; set; }
[RelatedDataAccessObjects]
public abstract RelatedDataAccessObjects<B> Bs { get; }
}
[DataAccessObject]
public abstract class B : DataAccessObject
{
[BackReference(Name = "", PrefixName = "", SuffixName = "")]
public abstract A Id { get; set; }
[PersistedMember]
public abstract string MoreData { get; set; }
}
这以某种方式创建了类似的架构(显然B中的Id现在不是主键),但是在我将数据填充到DB中之后,A中的Bs属性未填充引用。简单地将类型B的抽象属性放入A似乎也不起作用,因为同一列同时是外键和主键(Id)。
欢迎任何建议。
答案 0 :(得分:1)
您是否需要访问As的B集合?在我看来B是包含来自A
和B
的数据的“超类”。如果是这种情况,则只需将A
设为B
的主键即可。
[DataAccessObject]
public abstract class A : DataAccessObject<uint>
{
[PersistedMember(Name = "Id")]
public abstract override uint Id { get; set; }
[PersistedMember]
public abstract string Data { get; set; }
}
[DataAccessObject]
public abstract class B : DataAccessObject<A>
{
[PersistedMember(Name = "Id", PrefixName = "")]
public abstract override A Id { get; set; }
[PersistedMember]
public abstract string MoreData { get; set; }
}
请注意,我已经覆盖了Id
属性,以获取与SQL匹配的列名。默认值表示列名称:AId
和BId
由于主键是一个对象,因此在Shaolinq术语中称为“复杂主键”。您可以使用缩小的引用功能来检索对象,而只是将它们作为它们的主键而无需往返数据库(更多信息:https://github.com/tumtumtum/Shaolinq/wiki/Deflated-References)
您可以查询特定的B值:
// Need to define primary key using an anonymous object because it's not an uint but rather an A that contains an uint.
model.Bs.GetByPrimaryKey(new { Id = 100 } );
您还可以使用缩小的引用查询B的特定值:
model.Bs.GetByPrimaryKey(model.As.GetReference(100));
您还可以在普通的LINQ查询中使用引用:
model.Bs.Where(c => c.Id == model.As.GetReference(100) || c.Id == model.As.GetReference(101)).ToList();
您也可以直接在查询中访问嵌套/复杂的主键:
model.Bs.Where(c => c.Id.Id == 100 || c.Id.Id == 101).ToList();
请注意,由于复杂的主键被展平并存储在表B
上,因此上述三个查询不需要执行隐式连接。
返回B
时,无需往返查询即可访问B.Id.Id
,但是如果访问B.Id.Data
,则会导致B.Id
自动通过隐藏的数据库往返来膨胀。为避免这种情况,您可以使用Include
通过第一个查询自动将B.Id
膨胀。
model.Bs.Include(c => c.Id).Single(c => c.Id == model.As.GetReference(100));
或更简洁地说:
model.Bs.Include(c => c.Id).Single(c => c.Id.Id == 100);