Во втором коротком посте из серии SQLite-Net Extensions мы рассмотрим, как создавать отношения один-к-одному, используя этот крошечный ORM.
Это самый простой тип связи с базой данных. В качестве примера можно привести транспортное средство и свидетельство о регистрации — каждое транспортное средство имеет один и только одно свидетельство о регистрации, а одно свидетельство о регистрации связано с одним и только одним транспортным средством (за исключением некоторых чрезвычайных правовых норм в других странах, которые я не знаю 🙂).
Мы можем смоделировать это двумя способами:
- как односторонние отношения — в этом случае только один из концов отношений знает о другом
- как двусторонние (с инверсией) отношения — оба конца отношений знают друг о друге.
Один-к-одному без инверсии (в одну сторону)
Этот вид отношений выглядит следующим образом:
Мы используем его, когда предполагаем, что достаточно, чтобы Vehicle знал о RegistrationCertificate, но документ не обязательно должен знать, с каким автомобилем / мотором он связан (по крайней мере, напрямую).
Затем в коде мы создаем два класса моделей с использованием SQLite-Ne Extensionst:
[Table("RegistrationCertificates")]
public class RegistrationCertificate
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string RegistrationNumber { get; set; }
public string VIN { get; set; }
public string OwnerData { get; set; }
}
[Table("Vehicles")]
public class Vehicle
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Brand { get; set; }
public DateTime ProductionDate { get; set; }
public decimal EngineCapacity { get; set; }
[ForeignKey(typeof(RegistrationCertificate))]
public int RegistrationCertificateId { get; set; }
[OneToOne]
public RegistrationCertificate RegistrationCertificate { get; set; }
}
Здесь интересен атрибут ForeignKeyAttribute, определенный в свойстве RegistrationCertificateId. Это — как говорит его имя — внешний ключ к первичному ключу связанной сущности (типа RegistrationCertificate).
Само свойство связанной сущности украшено OneToOneAttribute.
Нам больше ничего не нужно делать, чтобы смоделировать эти отношения. Мы уже можем использовать это:
var db = new SQLiteConnection(new SQLitePlatformAndroid(), Constants.DbFilePath);
db.CreateTable<Vehicle>();
db.CreateTable<RegistrationCertificate>();
var vehicle = new Vehicle
{
Brand = "Renault",
EngineCapacity = 1.9m,
ProductionDate = new DateTime(2001, 01, 01)
};
var certificate = new RegistrationCertificate
{
RegistrationNumber = "AB 12345",
OwnerData = "Dawid Sibiński",
VIN = "1312BS1312ASDSSVVW"
};
db.Insert(vehicle);
db.Insert(certificate);
vehicle.RegistrationCertificate = certificate;
db.UpdateWithChildren(vehicle);
var vehicleStored = db.GetWithChildren<Vehicle>(vehicle.Id);
Здесь нет ничего особенного, верно? Это выглядит очень похоже на то, что мы видели в предыдущем посте об отношениях «многие ко многим». Что нас интересует, так это то, что в конце, когда объект Vehicle извлекается из базы данных с помощью метода GetWithChildren, его свойство RegistrationCertificate также заполняется:
Один-к-одному с инверсией (в обе стороны)
Этот вид отношений моделирует себя, как показано ниже:
Что действительно изменилось на диаграмме по сравнению с отношением без инверсии, так это то, что теперь RegistrationCertificate имеет свойство типа Vehicle (в коде — ссылка на объект, связанный с транспортным средством, и внешний ключ).
В нашем случае это еще более «реально» — было бы неплохо, если бы Транспортное средство узнало о своем Регистрационном Сертификате, но также когда мы смотрим на сертификат, нам бы хотелось узнать, к какому автомобилю он принадлежит.
Теперь мы можем смоделировать это в коде. Единственное, что изменяется в модельных классах — это добавление ссылочного и внешнего ключа к Vehicle в модели RegistrationCertificate, поэтому я представляю только обновленный код этого класса:
[Table("RegistrationCertificates")]
public class RegistrationCertificate
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string RegistrationNumber { get; set; }
public string VIN { get; set; }
public string OwnerData { get; set; }
// added to have Inversion relationship
[ForeignKey(typeof(Vehicle))]
public int VehicleId { get; set; }
[OneToOne]
public Vehicle Vehicle { get; set; }
}
Что здесь круто, так это то, что нам не нужно изменять наш код для сохранения сущностей со связями в базе данных SQLite. Мы можем просто добавить следующую строку в конце:
var certificateStored = db.GetWithChildren<RegistrationCertificate>(certificate.Id);
и обратите внимание, что certificateStored уже содержит связанный с ним объект Vehicle:
Резюме
В сегодняшнем коротком посте мы увидели, как создать отношения «один к одному» между двумя объектами в базе данных SQLite, используя SQLite-Net Extensions ORM. Это очень просто и не требует использования Entity Framework writing или написания SQL-запросов непосредственно в нашем коде.
Мы рассмотрели два типа отношений один-к-одному: односторонние и двусторонние. Выбор между этими двумя зависит от использования и цели отношений, которые мы моделируем.
Про отношение «многие ко многим» вы можете прочитать в этом посте.
Я надеюсь, что вы найдете это полезным однажды 😉
Не забудьте зайти на блог, там бывают полезные записи, которые я не публикую тут!
А чтобы быть в курсе последних моих постов, подписывайтесь на мой канал в Telegram.