Отношение в структуре сущности (сначала код) - PullRequest
1 голос
/ 15 марта 2012

У меня есть 2 таблицы:

tblInvestment
{
    InvestmentId char(10), --pk
    PrimaryPerformanceId char(10)
}

tblPerformance
{
    PerformanceId char(10), --pk,
    InvestmentId char(10)
}

И я создал 2 описания сущностей для этих двух таблиц:

[Table("tblInvestment")]
class Investment
{
    [Key]
    public string InvestmentId { get; set; }
    public string PrimaryPerformanceId { get; set; }

    [ForeignKey("PrimaryPerformanceId")]
    public virtual Performance PrimaryPerformance { get; set; }
    [ForeignKey("InvestmentId")]
    public virtual ICollection<Performance> Performances { get; set; }
}

[Table("tblPerformance")]
class Performance
{
    [Key]
    public string PerformanceId { get; set; }
    public string InvestmentId { get; set; }
    [ForeignKey("InvestmentId")]
    public virtual Investment Investment { get; set; }
}

Когда я создаю новую запись для каждой таблицы и вызываюФункция DbContext.SaveChanges, я получил исключение, говорит: « Невозможно определить действительный порядок для зависимых операций. Зависимости могут существовать из-за ограничений внешнего ключа, требований модели или сгенерированных в хранилище значений. » Но если яудалить свойство Investment.PrimaryPerformance, я могу сохранить записи в базе данных.Почему?

using(MyContext db = new MyContext)
{
    var inv = db.Investments.Add(new Investment{
        InvestmentId = "1",
        PrimaryPerformance = new Performance{
            PerformanceId = "A",
            InvestmentId = "1"
        }
    };
    db.SaveChanges();
}

Вот информация стека:

System.Data.Mapping.Update.Internal.UpdateTranslator.DependencyOrderingError (IEnumerable`1 remainder) System.Data.Mapping.Update.Internal.UpdateTranslator..SaveChanges (параметры SaveOptions) System.Data.Entity.Internal.InternalContext.SaveChanges () System.Data.Entity.Internal.InternalContext.SaveChanges () System.Data.Entity.Internal.LazyInternalContext.SaveChanges () System.Data.Entity.DbContext.SaveChanges ()

Ответы [ 4 ]

1 голос
/ 15 марта 2012

Я думаю, что проблема в вашей модели, где у вас есть двойной внешний ключ "Performance" ==>

[ForeignKey("PrimaryPerformanceId")]
public virtual Performance PrimaryPerformance { get; set; }
[ForeignKey("InvestmentId")]
public virtual ICollection<Performance> Performances { get; set; }

Я думаю, что вы должны удалить один из них ...

0 голосов
/ 19 марта 2012

Исключение выдается функцией TryTopologicalSort, я думаю, эта функция используется для определения зависимости между записями. Он поддерживает только одно отношение между сущностями.

0 голосов
/ 19 марта 2012

ОК, во-первых, вам нужно исправить вашу объектную модель, так как она дает вам неверную схему БД в том виде, в каком она сейчас стоит. Если вы посмотрите на полученную схему, вы увидите, что EF создал дополнительный InvestmentId (с именем Investment_InvestmentId) для tblPerformance. Все, что вам нужно сделать, это указать, что ваша связь между классами Investment и Performance, представленными в свойствах Investment.Performances и Performance.Investment, является двунаправленной.

Если вы предпочитаете аннотации данных по сравнению с текущими API (как это выглядит), вам нужно использовать атрибут InverseProperty , например:

[Table("tblPerformance")]
class Performance
{
    [Key]
    public string PerformanceId { get; set; }
    public string InvestmentId { get; set; }

    [InverseProperty("Performances")]
    public virtual Investment Investment { get; set; }
}


Теперь исключение, которое вы получаете, очень нормально. Подумайте об этом, вы просите EF добавить два объекта для вас в одной транзакции: объект инвестиций, у которого есть основной объект производительности, поэтому EF сначала пытается вставить запись производительности, чтобы получить PrimaryPerformanceId для объекта инвестиций (с InvestmentId = 1), но затем он отмечает, что для записи эффективности также необходим тот же объект Инвестиции (с Id = 1), что и для его Инвестиции. Какой из них пойдет первым? Невозможно в одной транзакции.

Поэтому единственный способ заставить его работать - это использовать две транзакции для добавления ваших объектов:

using(Context db = new Context())
{
    var inv = db.Investments.Add(new Investment() { InvestmentId = "1"});
    db.SaveChanges();

    inv.PrimaryPerformance = new Performance()
    {
        PerformanceId = "A",
        InvestmentId = "1"
    };
    db.SaveChanges();
}

И этот код работает просто отлично.

Примечание. Я использовал последнюю версию EF для запуска этого кода (v4.3.1). Поэтому, пожалуйста, обновите ваши двоичные файлы, если вы этого еще не сделали.

0 голосов
/ 15 марта 2012

Из MSDN:

Если размещено в свойстве внешнего ключа, имя связанного свойства навигации.Если оно помещено в свойство навигации, имя связанного внешнего ключа (ей).

Вам необходимо связать связанные поля только в одном классе (если они не соответствуют соглашениям об именах).Вы делаете это, чтобы сообщить Code First, что они принадлежат к одному и тому же отношению внешнего ключа.Тогда Code First достаточно умна, чтобы самостоятельно определить первичные ключи Relation, поскольку вы указали атрибут Key для связанных классов.

Таким образом, ваша модель должна выглядеть следующим образом:

[Table("tblInvestment")]
class Investment
{
    [Key]
    public string InvestmentId { get; set; }

    [ForeignKey("PrimaryPerformance")]
    public string PrimaryPerformanceId { get; set; } // This is the foreign key property           
    public virtual Performance PrimaryPerformance { get; set; } // This is the navigation property

    public virtual ICollection<Performance> Performances { get; set; }
}

[Table("tblPerformance")]
class Performance
{
    [Key]
    public string PerformanceId { get; set; }

    public virtual Investment Investment { get; set; }
}
...