Оптимистичный параллелизм с Entity Framework и MySQL - PullRequest
1 голос
/ 30 сентября 2011

В настоящее время я занимаюсь разработкой приложения с использованием Entity Framework 4.1 и MySQL. Я хочу использовать оптимистичный параллелизм и поэтому должен создать структуру таблицы, которая позволяет EF обнаруживать проблемы параллелизма. Моя цель примерно такая: http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx.

Моя проблема в том, что тип метки времени в MySQL отличается от MS SQL Server. В дополнение к этому ни метка времени, ни дата-время не обеспечивают точность менее секунды в MySQL (http://feedblog.org/2007/05/26/why-doesnt-mysql-support-millisecond-datetime-resolution/). Следовательно, эти типы будут очень плохими при обнаружении проблем параллелизма.

Какой другой тип данных я мог бы использовать для решения этой проблемы? Я думал о том, чтобы использовать Guid. Однако у этого подхода есть две потенциальные проблемы: 1. MySQL хранит Guids как char (36), что делает их очень неэффективными. 2. Я не уверен, что EF требует, чтобы версия строки строго увеличивалась или достаточно, чтобы она была уникальной.

Ответы [ 3 ]

3 голосов
/ 30 сентября 2011

Большое предупреждение: НЕ ИСПЫТАНО - просто мысли вслух.

EF поддерживает переопределение SaveChanges, поэтому, возможно, один из вариантовопределить интерфейс, такой как:

interface IVersionedRow {
    int RowVersion {get;set;}
}

и добавить свойство / поле int RowVersion как к классу (ам) вашей модели, так и к таблице (таблицам) базы данных, и использовать partial class для реализации этого интерфейса(используя неявную реализацию интерфейса):

partial class Customer : IVersionedRow {}
partial class Order : IVersionedRow {}
...

Затем переопределите SaveChanges, что-то вроде:

public override int SaveChanges(SaveOptions options)
{    
    foreach (ObjectStateEntry entry in
        ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
    {
        var v = entry.Entity as IVersionedRow;
        if(v != null) v.RowVersion++;
    }
    return base.SaveChanges(options);
}

, которая должна затем функционировать (теоретически - не проверено) как реализованная вручную строка -счетчик версий.Оставьте проверку изменений включенной для RowVersion, и это должно послужить.

1 голос
/ 03 мая 2018

Я только что отправил PR в MySQL .NET Connector v6.9.10 , который обеспечивает решение этой проблемы, которое обеспечивает оптимистическую блокировку между приложениями EF и не-EF.Подробнее см. https://stackoverflow.com/a/50147396/365261.

0 голосов
/ 29 сентября 2016

Это проверенное решение (для EF6 и выше).

Вот что вы должны сделать в вашей модели:

    [Table("some_table")]
    public class SomeEntity : IVersionedRow //define an interface as described previously and replace int type to long
    {
        ...
        [Column("row_version")]
        public long RowVersion { get; set; }
    }

Тогда в вашем контексте:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<SomeEntity>()
        .Property(p => p.RowVersion).IsConcurrencyToken();
    base.OnModelCreating(modelBuilder);
}

public override int SaveChanges()
{    
    var objectContextAdapter = this as IObjectContextAdapter;
    if (objectContextAdapter != null) {
        objectContextAdapter.ObjectContext.DetectChanges();
        foreach (ObjectStateEntry entry in objectContextAdapter.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)) {
            var v = entry.Entity as IVersionedRow;
            if (v != null) 
                v.RowVersion++;
        }
    }
    return base.SaveChanges();
}

Теперь, когда вы выполняете операцию обновления или удаления, незабудьте включить DbUpdateConcurrencyException .Это прекрасно работает для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...