Форум программистов, компьютерный форум, киберфорум
C#: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.68/25: Рейтинг темы: голосов - 25, средняя оценка - 4.68
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
MS SQL

Entity Framework + Repository, обновление данных

12.03.2015, 11:33. Показов 5533. Ответов 27
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет, помогите пожалуйста разобраться, вопрос по сути простой.

Имеем Entity Framework и простейший репозиторий (CRUD операции убрал для наглядности):

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Repository<T> : IRepository<T> where T : class
    {
        internal SalesAssistEntities context;        
        internal DbSet<T> dbSet;
 
        public Repository(SalesAssistEntities context)
        {
            this.context = context;
            this.dbSet = context.Set<T>();
 
        }
 
        public void Save()
        {
            context.SaveChanges();
        }
 
        public IEnumerable<T> GetAll()
        {
            return dbSet.ToList();
        }
 
    }
Сценарий:
  1. Наш репозиторий (context) запоняется после вызова функции GetAll()
  2. В базе данных происходят изменения
  3. Пользователь хочет получить актуальные данные, снова вызов функции GetAll()

И тут такая проблема. Новые, либо удалённые сущности, актуализируются на ура. Но изменения в уже загруженных сущностях не отображаются. Почему?

Пробил профайлер на базе, каждый раз при GetAll() идёт полная выборка таблицы. По идее данные доходят до контекста, но почему-то не обновляются сущности

Добавлено через 1 час 49 минут
Посмотрел. Практически все эти темы я уже до этого прочитал, там нет ответа на мой вопрос (

Добавлено через 18 часов 31 минуту
Ребят, пожалуйста, помогите найти в чём загвоздка. Без этого дальше разбираться не могу.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
12.03.2015, 11:33
Ответы с готовыми решениями:

Обновление данных в Entity Framework
Всем привет, помогите пожалуйста. вот есть такой код testentityEntities creat = new testentityEntities(); user...

Работа с Entity FrameWork обновление сущностей
Добрый день, у меня есть 2 сущности (работа и люди) со связкой 1 ко многим, есть необходимость менять связь сущности т.е. я хочу изменить у...

В чем разница между Entity Framework и Entity Framework Core?
В чем разница (если она есть) между entity framework и entity framework core?

27
 Аватар для Монфрид
1245 / 1055 / 293
Регистрация: 07.03.2012
Сообщений: 3,247
12.03.2015, 12:06
а где собственно код обновления, как вы обновляете
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
12.03.2015, 12:18  [ТС]
Данные обновляются в базе, я лишь хочу получить актуальные данные по вызову функции GetAll()

Однако я получаю лишь новые строки, уже загруженные сущности не обновляются, хотя с базы тянется вся таблица.
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
12.03.2015, 14:08
Цитата Сообщение от dSid Посмотреть сообщение
я лишь хочу получить актуальные данные по вызову функции GetAll()
dSid, ну так покажите как вы используете GetAll().
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
12.03.2015, 14:26  [ТС]
Вот так:

У меня есть unitOfWork, в котором хранятся репозитории и Longlife контекст. Все репозитории используют именно его.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UnitOfWork
    {
        private SalesAssist.Database.SalesAssistEntities context = new SalesAssist.Database.SalesAssistEntities();        
        private Repository<User> userRepository;
 
        public Repository<User> UserRepository
        {
            get
            {
 
                if (this.userRepository == null)
                {
                    this.userRepository = new Repository<User>(context);
                }
                return userRepository;
            }
        }
    }
Форма получает unitOfWork при инициализации.


C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public partial class Benutzerverwaltung : Form
    {
        private UnitOfWork unitOfWork;
        private BindingSource bsUsers = new BindingSource();
 
        public Benutzerverwaltung(UnitOfWork unitOfWork)
        {
            InitializeComponent();
            this.unitOfWork = unitOfWork;            
        }
        
        private void Benutzerverwaltung_Load(object sender, EventArgs e)
        {
            bsUsers.DataSource = unitOfWork.UserRepository.GetAll();
            myDataGridView.DataSource = bsUsers;
        }
 
        public void Refresh()
        {
            bsUsers.DataSource = unitOfWork.UserRepository.GetAll();
        }
 
    }
кнопка на форме вызывает Refresh(), при котором идёт выборка всей таблицы из базы (проверено!).
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
12.03.2015, 15:27
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 public Benutzerverwaltung(UnitOfWork unitOfWork)
 {
      InitializeComponent();
      this.unitOfWork = unitOfWork; 
      FillData();     
 }
 
public IEnumerable<object> DataSource \\это
{
     set
     {
         myDataGridView.DataSource = value;
         myDataGridView.Refresh();
     }
}
 
public void FillData()
{
   _view.DataSource = unitOfWork.UserRepository.GetAll(); \\сюда. Неизвестно же где у вас грида.
}
попробуйте так.

Добавлено через 39 минут
dSid, а вообще мне кажется можно было бы сделать по другому чуть-чуть
есть базовый сиквел репозиторий:
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
12.03.2015, 15:38  [ТС]
я не понял что это такое

C#
1
2
3
4
5
6
7
8
public IEnumerable<object> DataSource \\это
{
     set
     {
         myDataGridView.DataSource = value;
         myDataGridView.Refresh();
     }
}
и в какой момент будут данные из базы обновляться.

Сделаю пример и выложу его сюда.
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
12.03.2015, 15:48
dSid, а вообще мне кажется можно было бы сделать по другому чуть-чуть
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  public class SqlRepository<T> : IRepository<T> where T : class
    {
        public SqlRepository(DbContext context)
        {
            Context = context;
            ObjectSet = context.Set<T>();
        }
        public IQueryable<T> GetAll()
        {
            return ObjectSet;
        }
        public IQueryable<T> GetWhere(
                               Expression<Func<T, bool>> predicate)
        {
            return ObjectSet.Where(predicate);
        }
        public void Add(T newEntity)
        {
            ObjectSet.Add(newEntity);
        }
 
        public void Remove(T entity)
        {
            var entry = Context.Entry(entity);
            if (entry != null && entry.State != EntityState.Detached)
                ObjectSet.Remove(entity);
        }
 
        protected DbSet<T> ObjectSet;
        protected DbContext Context;
    }
Репозиторий user:
C#
1
2
3
4
5
6
7
8
9
10
11
public class UserRepository : SqlRepository<User>
    {
        public UserRepository (DbContext context) : base(context)
        {
        }
 
        public IEnumerable<User> GetUsers()
        {
            return GetWhere(c => c.Id > 0).ToList();
        }     
    }
Uow: в нем ты уже регистрируешь свой репозиторий
C#
1
2
3
4
5
6
7
8
9
10
public class UnitOfWork
{
 private SalesAssist.Database.SalesAssistEntities context = new SalesAssist.Database.SalesAssistEntities();        
 
 public UnitOfWork()
 {
      UserRepository  = new UserRepository (context)
 }
public UserRepository UserRepository  {get;set;}
}
А использовать UoW уже через какой-нибудь менеджер чтоб вытаскивать контекст наружу типа :
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 public class  Manager
    {
        private UnitOfWork _uow;
 
        public Manager()
        {
            _uow = new UnitOfWork();
        }
 
        public IEnumerable<User> GetUsers()
        {
            return _uow.UserRepository.GetUsers();
        }
}
а в UI уже:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Manager _manager;
public Benutzerverwaltung()
 {
      InitializeComponent();
      _manager = new Manager()
      FillData();     
 }
 
public IEnumerable<User> DataSource \\это
{
     set
     {
         myDataGridView.DataSource = value;
         myDataGridView.Refresh();
     }
}
 
public void FillData()
{
   _view.DataSource = _manager.GetUsers().ToList(); \\сюда. Неизвестно же где у вас грида.
}
ну и на слои разобрать чтоб все в ui не тащить

Добавлено через 3 минуты
Цитата Сообщение от dSid Посмотреть сообщение
я не понял что это такое
свойство, для удобства. Сразу заполняешь таблицу. Я не совсем понял зачем Вам тут:
C#
1
BindingSource bsUsers = new BindingSource();
заполняйте сразу таблицу

Добавлено через 2 минуты
Цитата Сообщение от dSid Посмотреть сообщение
и в какой момент будут данные из базы обновляться.
я думаю вы разберетесь с использование методов.
это:
C#
1
2
3
4
5
 public Benutzerverwaltung(UnitOfWork unitOfWork)
 {
      InitializeComponent();
      FillData();     
 }
вместо вот этого обработчика
C#
1
2
3
4
5
   private void Benutzerverwaltung_Load(object sender, EventArgs e)
        {
            bsUsers.DataSource = unitOfWork.UserRepository.GetAll();
            myDataGridView.DataSource = bsUsers;
        }
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
12.03.2015, 18:30  [ТС]
Вот готовый тест-проект, всё не нужное вырезано. Нужна лишь база Northwind.

Простой пример. Запустили прогу, сотрудники отобразились. Изменили сотрудника в базе вручную. Нажали обновить и... ничего не происходит. Почему?

FF_Repository_Test.zip
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
12.03.2015, 23:50
не знаю, что у вас там не получается..
создал свою таблицу, так быстрее..
есть у нас запись - отобразили:



заинсертили новую, рефрешим по кнопке - отобразили:



по поводу биндингСурса - зачем? и наглядная демонстрация свойства которое инкапсулирует некоторую логику грида:

0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
12.03.2015, 23:52
все адекватно рефрешится.
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
13.03.2015, 12:05  [ТС]
Спасибо большое за обстоятельный ответ. Конечно можно многое сделать по другому, это скорее уже концептуальный вопрос.

Цитата Сообщение от m@cChe Посмотреть сообщение
Я не совсем понял зачем Вам тут:

C#
1
BindingSource bsUsers = new BindingSource();
BindingSource мне нужен для того, чтоб не привязывать DAL непосредственно к UI, это мой BL. К тому же я работаю с гридом от DevExpress, а для этого удобнее DataSource, которая имплементирует IBindingList. Но это всё уже ньюансы. Как бы то ни было, даже если я привяжу грид непосредственно к репозиторию, проблема остаётся.

В вашем примере вы всё сделали правильно, новые, как и удалённые строчки отображаются без проблем. Однако, измените в базе уже загруженную сущность и попробуйте обновить грид! Вы не увидите своих изменений, в ЭТОМ то и вся проблема.
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
13.03.2015, 12:16
Цитата Сообщение от dSid Посмотреть сообщение
BindingSource мне нужен для того, чтоб не привязывать DAL непосредственно к UI
dSid, но получается, что привязали.. удалите из формы ссылку на DataModel и все, все рухнуло.

UI ничего не должен знать о DAL (только UoW) никаких ссылок на него и т.д

Цитата Сообщение от dSid Посмотреть сообщение
К тому же я работаю с гридом от DevExpress, а для этого удобнее DataSource
ммм.., а если вот так:

C#
1
2
3
4
5
6
7
8
9
//если я не ошибаюсь, то внутри devexpress контролл
 public IEnumerable<table> DataSource
        {
            set
            {
                gridControl1.DataSource = value; 
                gridView1.RefreshData();
            }
        }
а если увижу)))
даж перепишу на рабочем пк.

Добавлено через 4 минуты
В Вашем варианте (по крайней как написано в коде выше) вы тащите контекс наружу:

Цитата Сообщение от dSid Посмотреть сообщение
bsUsers.DataSource = unitOfWork.UserRepository.GetAll();
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
13.03.2015, 12:45  [ТС]
Цитата Сообщение от m@cChe Посмотреть сообщение
dSid, но получается, что привязали.. удалите из формы ссылку на DataModel и все, все рухнуло.
UI ничего не должен знать о DAL (только UoW) никаких ссылок на него и т.д
Погодите, но у меня нет там ссылки на DataModel, в моём примере UI о DAL ничего и не знает. Либо я сейчас что-то глобально не догоняю.

Не увидите, я уверен ))) Я уже неделю пытаюсь с этим разобраться. Казалось бы такой простой вопрос, ан нет...

Добавлено через 16 минут
Кажется я понял, что вы имеете ввиду. Мой репозиторий это так же DAL, и да, я работаю с ним непосредственно в UI, это вы мне хотели сказать?
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
13.03.2015, 12:59
бингооо

Добавлено через 22 секунды
Цитата Сообщение от dSid Посмотреть сообщение
я работаю с ним непосредственно в UI
ключевое
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
13.03.2015, 13:08  [ТС]
Понятно. Просто это тестовый проект, чтоб продемонстрировать поведение EF.
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
13.03.2015, 13:21
ну я вам скажу, что где-то вы напортачили в своей реализации.

1.
C#
1
2
3
4
 IEnumerable<T> Get(
            Expression<Func<T, bool>> filter = null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string includeProperties = "");
- это, что? выборка? лучше так -
C#
1
2
IQueryable<T> GetWhere(
                              Expression<Func<T, bool>> predicate);
- потом листу приводить.

2.вот соббсно класс формы :
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   private readonly UnitOfWork _uow;
        public Form1()
        {
            InitializeComponent();
            _uow = new UnitOfWork();
            FilData();                            //вот мы тут его используем и все норм, но только при инициализации.
        }
 
        public IEnumerable<Banks> DataSource
        {
            set
            {
                gridControl1.DataSource = value;
                gridView1.RefreshData();
            }
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            Reset();
        }
 
        private void FilData()
        {
            DataSource = _uow.EmployeeRepository.GetAll();//Ваш метод для отображения данных
        }
 
        private void Reset()
        {
            using (NorthwindEntities ctx = new NorthwindEntities())
            {
                DataSource = ctx.Banks.Where(c => c.Id > 0).ToList(); //а вот просто стандартный на мой взгляд метод для отображения, если не пытаться прикручивать свои DI реализации. И с ним все ресетиться))))
            }
        }
читаем комменты к коду

Добавлено через 1 минуту
что то вы не диспоузите, мне кажется.
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
13.03.2015, 13:45  [ТС]
По первому пункту реализации вообще нет, это так, кусок интерфейса на будущее, он тут вообще не учавствует.

А во втором вообще неразбериха. Сначала мы используем один контекст, который находится в UnitOfWork, для инициализации - прекрасно. А вот при вызове Reset, получаем следующее:

1. мы создаём совершенно новый контекст (и понятно что тогда грид нормально ресетится). Зачем? У нас уже есть один глобальный контекст для всего приложения.

2. мы опрашиваем его напрямую, в обход репозитория, не говоря уже о BL итд.

3. после Reset() контекст уничтожится и я не смогу записать в базу изменения.
0
 Аватар для m@cChe
45 / 45 / 26
Регистрация: 15.05.2013
Сообщений: 226
Записей в блоге: 1
13.03.2015, 13:48
Я вам пытаюсь донести то-что где то вы накосячили и надо разбираться. И не в коем случае не призываю использовать Reset() - он как пример, что все работает, а ошибка где-то в Вашем коде.
0
0 / 0 / 0
Регистрация: 11.03.2015
Сообщений: 14
13.03.2015, 14:05  [ТС]
Это изначально было понятно, что новый контекст получит обновлённые данные и создаст корректные сущности.

Вопрос как раз в том, почему этого не делает уже готовый контекст. В коде ошибки нет. Дело в понимании архитектуры и принципа работы EF.

Вот что я накопал:

When you use EF it by default loads each entity only once per context. The first query creates entity instace and stores it internally. Any subsequent query which requires entity with the same key returns this stored instance. If values in the data store changed you still receive the entity with values from the initial query. This is called Identity map pattern. You can force the object context to reload the entity but it will reload a single shared instance.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
13.03.2015, 14:05
Помогаю со студенческими работами здесь

Автообновление данных с Entity Framework
В составе C# и MSSQL пишу многопользовательскую программу (по сути простой учёт продукции на складах). Использую Entity Framework для...

Синхронизация баз данных Entity Framework
Добрый день! Есть две базы данных(SQL Express) одинаковые по структуре на двух разных машинах, на одной добавляются данные в базу на...

Entity Framework и загрузка данных в БД SQL CE
Доброго времени суток! Использую Entity Framework Code First и бд SQL CE 4.0. Пытаюсь прочитать данные в потоке и записать их в бд. Делаю...

Entity Framework не создает базу данных
Здравствуйте. возникла какая-то непонятная проблема. работал с проектом в visual studio (база создавать через code first entity framework),...

Копирование база данных. Entity Framework
Привет, есть удалённая база данных, есть локальная. Локальная база данных служит исключительно только для чтения. Я хочу скопировать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru