首页 > 解决方案 > Servicestack Ormlite - 弱/通用引用(如 nhibernate 中的 ReferencesAny)

问题描述

在 nHibernate 中,您可以将列声明为object并将其映射为弱引用:

public virtual object TableRef{get;set;}

// then in the fluent mapping:
ReferencesAny(x => x.TableRef)

您将如何在 Servicestack ormlite 中实现这种映射

更新 我有条件参考需求。我想在一个字段中引用 3 个实体。所以当我查询数据库时,我会得到正确的参考。

public class UserEntity{

   public long Id {get;set;}
   public object MyPrimaryAnimal {get;set;}
} 

MyPrimaryAnimal也许:CatEntityDogEntityBirdEntity

这是我能想到的最好的用例。弱参考。(我有 ormlite 许可证)

谢谢

标签: weak-referencesormlite-servicestack

解决方案


就我个人而言,我不喜欢未知/无类型属性,所以我永远不会尝试将未知类型推入单个无类型字段。我的第一个偏好是使用单个平面具体结构,类似于您已经设计 RDBMS 表的方式,其中包含不同列的单个平面表,捕获您想要捕获的所有信息,或者在实体表本身上:

public class UserEntity
{
   public long Id { get; set; }
    //.. flattened properties of everything you want captured
}

或者,如果我需要在多个表上捕获相同的信息,一个具有您想要捕获的所有属性的类,例如:

public class UserEntity
{
   public long Id { get; set; }
   //[Reference] // Optional: Save in external Animal table
   public Animal MyPrimaryAnimal {get;set;}
}

public class Animal
{
    public string Type { get; set; } // e.g. Cat, Dog, Bird
    //.. flattened properties of everything you want captured
}

复杂类型属性会在 OrmLite 中自动添加,或者您可以添加[Reference]属性以获取 OrmLite 的 POCO 引用支持,以将数据持久保存在外部Animal表中。

您需要在UserEntityAnimal类上添加 FK 引用,以实现像这样的 1:1 映射

不同的混凝土类型属性

我的第二个偏好是为我想要存储的每个不同属性设置不同的类型属性,例如:

public class UserEntity
{
   public long Id { get; set; }
   public CatEntity CatEntity { get; set; }
   public DogEntity DogEntity { get; set; }
   public BirdEntity BirdEntity { get; set; }
} 

UserEntity然后一切都正常工作,当您保存在 OrmLite 中时,您将始终处理具体类型,这将在幕后破坏复杂类型。

在对象字典中保存未知的基本类型

如果我绝对需要在单个字段中存储不同的实体,我会将其存储到对象字典中并提供一个类型化的包装器来持久/检索基本实体类型,例如:

public class UserEntity
{
    public long Id { get; set; }

    [DataAnnotations.Ignore]
    public AnimalEntity MyPrimaryAnimal
    {
        get => AnimalEntity.FromObjectDictionary(AnimalRef);
        set => AnimalRef = value.ToObjectDictionary();
    }

    public Dictionary<string, object> AnimalRef { get; set; }
}

AnimalEntity将包含所有基本类型属性和工厂函数,以基于Type标识符返回具体类型,例如:

public class AnimalEntity
{
    public string Type => GetType().Name;

    public static AnimalEntity FromObjectDictionary(Dictionary<string, object> props)
    {
        if (props == null) return null;
        var type = props[nameof(Type)];
        switch (type) 
        {
            case nameof(DogEntity):
                return props.FromObjectDictionary<DogEntity>();
            case nameof(CatEntity):
                return props.FromObjectDictionary<CatEntity>();
            case nameof(BirdEntity):
                return props.FromObjectDictionary<BirdEntity>();
            default:
                throw new NotSupportedException($"Unknown Animal '{type}'");
        }
    }
}

然后,您可以拥有任意数量的子类型:

public class CatEntity : AnimalEntity
{
    public int Id { get; set; }
    public string Cat { get; set; }
}

public class DogEntity : AnimalEntity
{
    public int Id { get; set; }
    public string Dog { get; set; }
}

public class BirdEntity : AnimalEntity
{
    public int Id { get; set; }
    public string Bird { get; set; }
}

您可以保存和检索为类型实体,例如:

db.Insert(new UserEntity {Id = 1, MyPrimaryAnimal = new BirdEntity {Id = 1, Bird = "B"}});
db.Insert(new UserEntity {Id = 2, MyPrimaryAnimal = new CatEntity {Id = 1, Cat = "C"}});
db.Insert(new UserEntity {Id = 3, MyPrimaryAnimal = new DogEntity {Id = 1, Dog = "D"}});

var results = db.Select<UserEntity>();
var animals = results.OrderBy(x => x.Id).Map(x => x.MyPrimaryAnimal);

animals[0] //= BirdEntity 
animals[1] //= CatEntity 
animals[2] //= DogEntity 

外部参考

如果我只需要一个字段来存储对单个字段中任何实体的引用,则通常使用 urn

public class UserEntity
{
    public long Id { get; set; }

    public string AnimalRef { get; set; }
}

您可以使用 ServiceStack 的IdUtils.CreateUrn<T>API 或ToUrn<T>扩展方法:

db.Insert(new UserEntity {Id = 1, AnimalRef = 1.ToUrn<BirdEntity>() });
db.Insert(new UserEntity {Id = 2, AnimalRef = 2.ToUrn<CatEntity>() });
db.Insert(new UserEntity {Id = 3, AnimalRef = 3.ToUrn<DogEntity>() });

这将保存以下字符串引用:

urn:birdentity:1
urn:catentity:2
urn:dogentity:3

如果要加载引用,则需要一个辅助函数来拆分骨灰盒,匹配类型并按 Id 返回实体引用。


推荐阅读