少林一对一关系

时间:2018-10-24 00:18:08

标签: c# orm

我正在使用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)。

欢迎任何建议。

1 个答案:

答案 0 :(得分:1)

您是否需要访问As的B集合?在我看来B是包含来自AB的数据的“超类”。如果是这种情况,则只需将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匹配的列名。默认值表示列名称:AIdBId

由于主键是一个对象,因此在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);