weak-references - 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
也许:CatEntity
,DogEntity
或BirdEntity
。
这是我能想到的最好的用例。弱参考。(我有 ormlite 许可证)
谢谢
解决方案
就我个人而言,我不喜欢未知/无类型属性,所以我永远不会尝试将未知类型推入单个无类型字段。我的第一个偏好是使用单个平面具体结构,类似于您已经设计 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
表中。
您需要在
UserEntity
或Animal
类上添加 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 返回实体引用。
推荐阅读
- android - 无法在android中的应用购买产品数据中显示
- c++ - C ++在主线程中等待将来没有while(true)
- html - 如何在 HTML 导航栏中居中对齐项目并右对齐项目,同时将左侧留空?
- ansible - Ansible 模式是 YAML 的一个特性吗?
- ios - 按月顺序填充 TableView 部分中的对象
- android - 从列表中删除重复项?
- php - 在块中使用函数,PHP
- python - ValueError:无法解释输入“幸存”
- java - 如果我不断为每个对象返回相同的哈希码,Hashmap 是否会成为链接列表
- python - 注释掉控制语句时有没有办法保持缩进