我个人不喜欢未知/未类型化的属性,因此我永远不会尝试将未知类型推入单个未类型化的字段中。我的第一个偏好是使用单一的平面混凝土结构,类似于您已经设计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's POCO References support,以使数据持久保存在外部Animal
表中。
对于这样的1:1映射,您需要在UserEntity
或Animal
类上添加FK引用
不同的混凝土类型属性
我的第二个首选项将为我要存储的每个不同属性具有不同的类型化属性,例如:
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
标识符返回具体的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; }
}
您可以保存和检索为Typed实体,例如:
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
外部参考
如果我只需要一个字段就可以在单个字段中存储对任何实体的引用,那么通常会使用a
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返回实体引用。
本文链接:https://www.f2er.com/2690555.html