Сбой ограничения FOREIGN KEY при попытке удалить объект, на который есть ссылка в объекте значения - PullRequest
0 голосов
/ 24 января 2020

Область интересов

Я пишу программное обеспечение для POS. Он имеет понятие средства для перевода денег , некоторые из которых физические .

Каждое физическое средство допускает несколько деноминаций , которые по существу являются комбинацией номинальной стоимости и фиатной валюты . Пример: 1 доллар США, 5 евро, 10 швейцарских франков и т. Д. c.

Валюта - это отдельное юридическое лицо, которое живет (для других целей) без каких-либо средств для денежных переводов. С другой стороны, деноминации зависят от одного среднего денежного перевода.

Текущее состояние реализации

До сих пор я успешно смоделировал этот домен в своей модели

public abstract class FiatCurrency : AggregateRoot
{
    private IList<Denominations> Denominations { get; }
    public virtual Currency Currency { get; }

    public static class Expressions
    {
        public static readonly Expression<Func<FiatCurrency, IEnumerable<Denominations>>> Denominations = x => x.Denominations;
    }

    public FiatCurrency(Currency currency)
    {
        Currency = currency;
    }

    protected FiatCurrency() { }
}

public abstract class PhysicalMoneyTransferMean : MoneyTransferMean
{
    private readonly IList<Denominations> _denominations;
    public virtual IReadOnlyList<Denominations> Denominations => _denominations.ToList();

    public PhysicalMoneyTransferMean(MoneyTransferMeanDirection direction, IList<ForeignCurrency> extraCurrencies, IDictionary<FiatCurrency, List<FaceValue>> denominations)
        : base(direction, extraCurrencies)
    {
        _denominations = denominations.Select(kv => new Denominations(this, kv.Key, kv.Value)).ToList();
    }

    protected PhysicalMoneyTransferMean() { }
}

public class Denominations : Entity
{
    public virtual PhysicalMoneyTransferMean MoneyTransferMean { get; }
    public virtual FiatCurrency Currency { get; }
    private string FaceValuesInternal { get; }
    public virtual IReadOnlyList<FaceValue> FaceValues => FaceValuesInternal.Split(';').Select(f => new FaceValue(f)).ToList();

    public static class Expressions
    {
        public static readonly Expression<Func<Denominations, object>> FaceValues = x => x.FaceValuesInternal;
    }

    public Denominations(PhysicalMoneyTransferMean moneyTransferMean, FiatCurrency currency, IEnumerable<FaceValue> faceValues)
    {
        MoneyTransferMean = moneyTransferMean;
        Currency = currency;
        FaceValuesInternal = string.Join(";", faceValues);
    }

    protected Denominations() { }
}

Отображения:

public class FiatCurrencyMap : ClassMap<FiatCurrency>
{
    public FiatCurrencyMap()
    {
        Id(Entity.Expressions<FiatCurrency>.Id);
        Map(c => c.Currency)
            .CustomType<CurrencyUserType>();
        HasMany(FiatCurrency.Expressions.Denominations)
            .KeyColumn("CurrencyId")
            .Inverse()
            .Cascade.All()
            .Not.LazyLoad();
        DiscriminateSubClassesOnColumn("Type");
    }
}


public sealed class PhysicalMoneyTransferMeanMap : SubclassMap<PhysicalMoneyTransferMean>
{
    public PhysicalMoneyTransferMeanMap()
    {
        HasMany(x => x.Denominations)
            .KeyColumn("MoneyTransferMeanId")
            .Cascade.All()
            .Not.LazyLoad()
            .Access.CamelCaseField(Prefix.Underscore);
    }
}

public sealed class DenominationsMap : ClassMap<Denominations>
{
    public DenominationsMap()
    {
        Id(Entity.Expressions<Denominations>.Id);
        References(x => x.MoneyTransferMean);
        References(x => x.Currency);
        Map(Denominations.Expressions.FaceValues)
            .Column(nameof(Denominations.FaceValues));
    }
}

Пока все хорошо, приведенное выше отображение дает следующую структуру базы данных (я на SQLite):

CREATE TABLE "FiatCurrency" (Id  integer primary key autoincrement, Type TEXT not null, Currency TEXT not null, ExchangeRateToLocalCurrency NUMERIC)

CREATE TABLE "MoneyTransferMean" (Id  integer primary key autoincrement, Type TEXT not null, Direction INT not null)

CREATE TABLE "Denominations" (Id  integer primary key autoincrement, FaceValues TEXT not null, MoneyTransferMeanId BIGINT not null, CurrencyId BIGINT not null, constraint FK_F2F07762 foreign key (MoneyTransferMeanId) references "MoneyTransferMean", constraint FK_B0AA916 foreign key (CurrencyId) references "FiatCurrency")

Проблема

При удалении средства денежного перевода из NHibernate также успешно удаляет связанные деноминации, однако при удалении бумажной валюты я получаю следующее («очевидное») сообщение:

could not execute update query[SQL: delete from "FiatCurrency" where Type='Local' and ?=1] ---> System.Data.SQLite.SQLiteException: constraint failed FOREIGN KEY constraint failed

Мой вопрос Как я могу сказать NHibernate удалить все деноминации, ссылающиеся на указанную валюту при удалении самой указанной валюты?

1 Ответ

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

Вы можете использовать Каскадную стратегию, используя FluentNHibernate:

FluentNHibernate

 public class FiatCurrencyGroupMap : ClassMap<FiatCurrencyGroup>
 {
  public FiatCurrencyGroupMap()
  {
     Id(x => x.Id);
     HasMany<Denomination>(x => x.Denominations)
        .Cascade.All();
  }
}

В качестве временного решения вы также можете сначала удалить Деноминации, а затем удалить FiatCurrency из БД.

...