Есть ли способ АВТОМАТИЧЕСКОГО отслеживания изменения Навигационного свойства для внешнего ключа при ДОБАВЛЕНИИ новых данных?

Возьмём самый простой пример.

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int CompanyId { get; set; } //внешний ключ

    public Company Company { get; set; }  // навигационное свойство
}
using (ApplicationContext db = new ApplicationContext())
{
    var company = db.Companies.First();

    try
    {
        User tom = new User { Name = "Tom", Company = company };
        db.Users.Add(tom);
        db.SaveChanges();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Допустим, что после чтения данных из БД company= db.Companies.First(), кто-то ПОМЕНЯЛ название компании.
И тогда при выполнении кода

User tom = new User { Name = "Tom", Company = company };
db.Users.Add(tom);
db.SaveChanges();

никак не отслеживается, что company ПОМЕНЯЛАСЬ!

Есть ли способ АВТОМАТИЧЕСКОГО отслеживания изменились ли данные в таблице Company? Что-то на подобие атрибутов [Timestamp] и [ConcurrencyCheck]?

Или каждый раз придётся самому проверять все навигационные свойства что они изменились?

Как правильно делать это на практике? В больших БД.


Ответы (1 шт):

Автор решения: Alexander Petrov

Можно использовать повышенный уровень изоляции транзакций.
В этом случае другие транзакции не смогут вклиниться между нашими First и SaveChanges.

using (var db = new ApplicationContext())
{
    var tran = db.Database.BeginTransaction(IsolationLevel.Serializable);
    
    var company = db.Companies.First(c => c.Name == "A");

    try
    {
        User tom = new User { Name = "Tom", Company = company };
        db.Users.Add(tom);
        db.SaveChanges();

        tran.Commit();
    }
    catch (Exception ex)
    {
        tran.Rollback();
        MessageBox.Show(ex.Message);
    }
}

Оправдано ли это - я не уверен. Ведь название компании всё равно может быть изменено уже после выполнения этого кода. Конечно, где-то в истории (если она ведётся) могут остаться правильные записи.


Чистый EF Core не позволяет делать вставки с условиями на стороне сервера.
Я советую посмотреть на ORM linq2db. Она позволяет такие инсёрты.
Понимаю, понимаю... Перейти на другую (правильную) ОРМ (вместо кривой) - это немыслимое дело. Но тогда хотя бы используйте расширение linq2db.EntityFrameworkCore . Оно включено в официальный список EF Core Tools & Extensions.

→ Ссылка