Служебный пакет Ormlite - слабая ссылка / ссылка generi c (например, ReferencesAny в nhibernate) - PullRequest
1 голос
/ 29 января 2020

В 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)

Спасибо

1 Ответ

2 голосов
/ 31 января 2020

Лично мне не нравятся неизвестные / нетипизированные свойства, поэтому я никогда не буду пытаться засунуть неизвестные типы в одно нетипизированное поле. Моим первым предпочтением было бы использовать одну плоскую бетонную структуру, аналогично тому, как вы уже проектировали бы таблицы СУБД с одной плоской таблицей из разных столбцов, собирающей всю информацию, которую вы хотите захватить, либо в самой таблице сущностей:

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], чтобы подключить Ссылки POCO OrmLite поддерживают , чтобы данные сохранялись во внешней таблице Animal.

Вам потребуется добавить ссылку на FK в классе UserEntity или Animal для таких отображений 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}'");
        }
    }
}

Тогда вы можете иметь столько подтипов, сколько вы будете иметь sh:

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; }
}

Который вы можете использовать IdUtils.CreateUrn<T> API ServiceStack или метод расширения 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.

...