Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.86/21: Рейтинг темы: голосов - 21, средняя оценка - 4.86
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288

Поместить переписку в БД

14.11.2019, 12:48. Показов 4329. Ответов 28

Студворк — интернет-сервис помощи студентам
Здрасте всем, дела обстоят так, сделал и настроил переписку между пользователями, но все это в режиме реального времени, т.е. без участия базы данных, в целом на проект можете посмотреть тут: Сервер Фронтенд
Далее хочу сделать чтобы это работало так - пользователи переписываются, один отключается, второй продолжает писать, и когда первый вошел сново в сеть, он мог открыть чат и увидеть написанное ранее и всю переписку в целом. Не могу разобрать устройство таблицы в бд и как доставать оттуда нужную переписку... Буду рад любой помощи.
Теперь пробежим по коду:
Серверная часть:
Сам ХАБ:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ChatHub : Hub
    {   
        [Authorize]
        public async Task SendToAll(string name, string message, string to)
        {
            var userName = Context.User.Identity.Name;
 
            if (Context.UserIdentifier != to) // если получатель и текущий пользователь не совпадают
                await Clients.User(Context.UserIdentifier).SendAsync("Receive", name, message, userName);
            await Clients.User(to).SendAsync("Receive", name, message, userName);
        }
        
    }
провайдер:
C#
1
2
3
4
5
6
7
8
9
public class CustomUserIdProvider : IUserIdProvider
    {
        public virtual string GetUserId(HubConnectionContext connection)
        {
            return connection.User?.Identity.Name;
            // или так
            //return connection.User?.FindFirst(ClaimTypes.Name)?.Value;
        }
    }
Конфигурация в стартапе:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IUserIdProvider, CustomUserIdProvider>();
            services.AddSignalR();
            services.AddCors(options =>
            {
                options.AddPolicy("EnableCORS", builder =>
                {
                    builder.                    
                    AllowAnyOrigin().
                    AllowAnyHeader().
                    AllowAnyMethod().
                    WithOrigins("http://localhost:4200").
                    AllowCredentials();
                });
            });
            services.AddScoped<DBUserContext>();
 
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
 
                    ValidIssuer = "http://localhost:5000",
                    ValidAudience = "http://localhost:5000",
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345"))
                };
                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];
 
                        // если запрос направлен хабу
                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) &&
                             (path.StartsWithSegments("/chat")))
                        {
                            // получаем токен из строки запроса
                            context.Token = accessToken;
                        }
                        return Task.CompletedTask;
                    }
                };
            });
            
            
 
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }
Как вы могли догадаться, все действия между клиентской частью и сервером ведутся через JWT-токены.
ну и контекст БД:
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
public class DBUserContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Friends> Friendships { get; set; }
 
        public DBUserContext()
        {
            Database.EnsureCreated();
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Friends>()
                .HasKey(t => new { t.UserId, t.FriendId });
 
            modelBuilder.Entity<Friends>()
                .HasOne(sc => sc.User)
                .WithMany(c => c.UserFriends)
                .HasForeignKey(sc => sc.FriendId);
 
            modelBuilder.Entity<Friends>()
                .HasOne(sc => sc.Friend)
                .WithMany(s => s.WhoAddMe)
                .HasForeignKey(sc => sc.FriendId);
        }
 
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=SocNW;Trusted_Connection=True;");
        }
    }
Клиент написан на Angular 8, вот компонент который в принципе и делает всю работу чата на клиенте:
JavaScript
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { HubConnection, HubConnectionBuilder } from '@aspnet/signalr';
import * as signalR from '@aspnet/signalr';
import { User } from 'app/user';
import { ActivatedRoute } from '@angular/router';
 
@Component({
  selector: 'app-chat',
  templateUrl: './chat.component.html'
})
export class ChatComponent implements OnInit {
  constructor(private http: HttpClient, activeRoute: ActivatedRoute) {
    this.id = Number.parseInt(activeRoute.snapshot.params["id"]);
  }
 
  private _hubConnection: HubConnection;
  user: User;
  id: number;
  userForMessage: User;
 
  message = '';
  messages: string[] = [];
  
  
  
 
  public sendMessage(): void {
    this._hubConnection
      .invoke('SendToAll', this.user.userName, this.message, this.userForMessage.userName)
      .then(() => this.message = '')
      .catch(err => console.error(err));
  }
  ngOnInit() {
 
    //this.nick = window.prompt('Your name:', 'John');
    let token = localStorage.getItem("jwt");
 
    //Получаем юзера, которому отправляем сообщение
    this.http.get(`http://localhost:5000/api/user/getuserformessage/${this.id}`
     ).subscribe((response: User) => {
        this.userForMessage = response;
      }, err => {
        console.log(err)
        });
 
    //Юзер который отправляет сообщение
    this.http.get("http://localhost:5000/api/customers/getidenti", {
      headers: new HttpHeaders({
        "Authorization": "Bearer " + token,
        "Content-Type": "application/json"
      })
    }).subscribe((response: User) => {
      this.user = response;
    }, err => {
      console.log(err)
    });
 
    let hubUrl = 'http://localhost:5000/chat';
    this._hubConnection = new signalR.HubConnectionBuilder()
      .withUrl(hubUrl, { accessTokenFactory: () => token })
      
      .build();
 
    this._hubConnection
      .start()
      .then(() => console.log('Connection started!'))
      .catch(err => console.log('Error while establishing connection :('));
 
    this._hubConnection.on('Receive', (nick: string, receivedMessage: string) => {
      const text = `${nick}: ${receivedMessage}`;
      this.messages.push(text);
    });
  }
 
}
Буду признателен любой помощи!
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
14.11.2019, 12:48
Ответы с готовыми решениями:

Загрузка изображений в переписку ВК
Здравствуйте, появилась задача - загрузить фотоснимки в общую переписку ВКонтакте. Текст сообщения получалось отправлять без проблем,...

Показываем переписку тикета
Нужна помощь, не знаю как разделить стили сообщение админа от пользователей, то есть что бы у админа можно было настраивать свой код, а у...

Хочу восстановить переписку в контакте
Помогите разобраться, возможно ли это? Хочу восстановить переписку в контакте недельной давности. Вдаваться в подробности сей...

28
Костыли любой сложности
201 / 146 / 36
Регистрация: 27.10.2019
Сообщений: 843
14.11.2019, 12:53
Lucky64, предлагаю организовать бд по типу чата, то есть ид,таймштамп,никнейм,сообщение
ну и при подключении доставать только то что нужно для текущего отображения, при прокрутке, доставать больше

если вопрос в прочитанности юзером сообщений то нужна ещё бд юзеров по типу ид,никнейм,таймштамп и беря от туда таймштамп тянуть из первой таблы записи

можно ещё хитрым способом в первую таблу писать дисконект юзера и тянуть данные после него
0
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
15.11.2019, 09:51  [ТС]
Цитата Сообщение от User-ganz Посмотреть сообщение
предлагаю организовать бд по типу чата, то есть ид,таймштамп,никнейм,сообщение
в данной таблице отсутствует айди пользователя, которому предназначается сообщение, в целом сохранить сообщение в базе это не проблема, не получается составить план, как мы будем определять кому именно оно предназначается, и как его достать

Добавлено через 3 минуты
User-ganz, плюс у нас уже есть таблица друзей, вот думаю может добавить туда список сообщений между этими друзьями, что то типа - List <string> Messages и потом пополнять, либо создать модель сообщения... крч пока разобрался с сигналР, ткая каша в голове

Добавлено через 4 часа 2 минуты
User-ganz, собрал из г..на и палок вот такое ... даже не знаю как назвать...
На сервере:
Модель
C#
1
2
3
4
5
6
7
public class Message
    {
        public int Id { get; set; }
        public int UserId { get; set; }
        public int FriendId { get; set; }
        public string SentMessage { get; set; }
    }
Контекст в бд
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 DBUserContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Friends> Friendships { get; set; }
        public DbSet<Message> Messages { get; set; } //Вот тут хранится переписка
 
        public DBUserContext()
        {
            Database.EnsureCreated();
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Friends>()
                .HasKey(t => new { t.UserId, t.FriendId });
 
            modelBuilder.Entity<Friends>()
                .HasOne(sc => sc.User)
                .WithMany(c => c.UserFriends)
                .HasForeignKey(sc => sc.FriendId);
 
            modelBuilder.Entity<Friends>()
                .HasOne(sc => sc.Friend)
                .WithMany(s => s.WhoAddMe)
                .HasForeignKey(sc => sc.FriendId);
        }
 
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=SocNW;Trusted_Connection=True;");
        }
    }
Метод добавления сообщений в бд
C#
1
2
3
4
5
6
7
8
9
[HttpGet("[action]/{id}"), Route("sevemessage")]
        [HttpGet("[action]/{id}/{message}"), Route("sevemessage")]
        public void SeveMessage(int id, string message)
        {
            User currentUser = db.Users.FirstOrDefault(x => x.UserName == User.Identity.Name);
            User recipient = db.Users.FirstOrDefault(x => x.Id == id);
            db.Messages.Add(new Message { UserId = currentUser.Id, FriendId = recipient.Id, SentMessage = message });           
            db.SaveChanges();           
        }
Достаю нужные сообщения и отправляю все это списком клиенту
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[HttpGet("[action]/{id}"), Route("sevemessage")]
        [HttpGet("[action]/{id}/{friendid}"), Route("sevemessage")]
        public IActionResult GetMessages(int id, int FriendId)
        {
            List<string> mesages = new List<string>();
            User User = db.Users.FirstOrDefault(x => x.Id == id);
            string username = User.UserName;
            User Friend = db.Users.FirstOrDefault(x => x.Id == FriendId);
            string friendname = Friend.UserName;
            foreach (var i in db.Messages)
            {
                if(i.UserId==id && i.FriendId == FriendId)
                {
                    mesages.Add($"{username} {i.SentMessage}");
                    
                }
                else if (i.FriendId == id && i.UserId == FriendId)
                {
                    mesages.Add($"{friendname} {i.SentMessage}");
                }
            }
            return Ok(mesages);
        }
На клиенте принимаю список
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
public getmessages() {
    let token = localStorage.getItem("jwt");
    this.http.get(`http://localhost:5000/api/messages/GetMessages/${this.user.id}/${this.userForMessage.id}`, {
      headers: new HttpHeaders({
        "Authorization": "Bearer " + token,
        "Content-Type": "application/json"
      })
    }).subscribe((response: string[]) => {
      this.messages = response;
    }, err => {
      console.log(err)
    });
  }
по факту все работает, история сохраняется, все как бы гут, но почему то кажется, что так не пойдет... что скажете?
0
Костыли любой сложности
201 / 146 / 36
Регистрация: 27.10.2019
Сообщений: 843
16.11.2019, 12:01
Lucky64, в таком случае просто добавляем к таблице с сообщениями ещё один столбец с идшками\именами адресатов, и делаем выборку по LIKE но не забываем о похожести те о необходимости разделителя тк лайк 1 выберет и 111 но не лайк ' 1 '
0
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
17.11.2019, 10:50  [ТС]
Цитата Сообщение от User-ganz Посмотреть сообщение
в таком случае просто добавляем к таблице с сообщениями ещё один столбец с идшками\именами адресатов, и делаем выборку по LIKE но не забываем о похожести те о необходимости разделителя тк лайк 1 выберет и 111 но не лайк ' 1 '
немного не понял, вот у меня таблица с сообщениями:
C#
1
2
3
4
5
6
7
public class Message
    {
        public int Id { get; set; }// Айди самого сообщения
        public int UserId { get; set; }// Айди от кого сообщение
        public int FriendId { get; set; }// Айди Адресата
        public string SentMessage { get; set; }//Само сообщение
    }
C#
1
public int FriendId { get; set; }
- это ведь и есть айдишник адресата?)

Добавлено через 8 минут
И еще такой вопрос, если вы заметили то таблица сообщений никак не связана с юзерами, т.е. у нее есть все айдишники итп, но всю связь я делаю вручную через
Метод добавления сообщений в бд:
C#
1
2
3
4
5
6
7
8
9
[HttpGet("[action]/{id}"), Route("sevemessage")]
        [HttpGet("[action]/{id}/{message}"), Route("sevemessage")]
        public void SeveMessage(int id, string message)
        {
            User currentUser = db.Users.FirstOrDefault(x => x.UserName == User.Identity.Name);
            User recipient = db.Users.FirstOrDefault(x => x.Id == id);
            db.Messages.Add(new Message { UserId = currentUser.Id, FriendId = recipient.Id, SentMessage = message });           
            db.SaveChanges();           
        }
И Достаю нужные сообщения и отправляю все это списком клиенту:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[HttpGet("[action]/{id}"), Route("sevemessage")]
        [HttpGet("[action]/{id}/{friendid}"), Route("sevemessage")]
        public IActionResult GetMessages(int id, int FriendId)
        {
            List<string> mesages = new List<string>();
            User User = db.Users.FirstOrDefault(x => x.Id == id);
            string username = User.UserName;
            User Friend = db.Users.FirstOrDefault(x => x.Id == FriendId);
            string friendname = Friend.UserName;
            foreach (var i in db.Messages)
            {
                if(i.UserId==id && i.FriendId == FriendId)
                {
                    mesages.Add($"{username} {i.SentMessage}");
                    
                }
                else if (i.FriendId == id && i.UserId == FriendId)
                {
                    mesages.Add($"{friendname} {i.SentMessage}");
                }
            }
            return Ok(mesages);
        }
т.е. все действия делаются с помощью ручного присваивания и добавления через ифы, это вообще приемлемо?
0
Эксперт .NET
 Аватар для Usaga
14313 / 9393 / 1355
Регистрация: 21.01.2016
Сообщений: 35,425
17.11.2019, 11:00
Lucky64, а я бы немного изменил модель данных. Ввёл бы сущность "Адресат" и из сущности "Message" ссылался бы на неё. "Адресат" бы содержал коллекцию пользователей. Так, если в этой коллекции один пользователь - сообщение приватное, если несколько - то сообщение групповое. Таким образом чатик начнёт поддерживать комнаты \ группы как во всяких телеграммах\ватсапах\слаках и прочих подобных штуках.

Добавлено через 5 минут
И вообще, не смотря на то, что я ангуляр очень люблю и уважаю, с выходом .NET Core 3 стоит попробовать использовать Blazor Server Side. Тогда у вас и фронт-энд будет на C#. Круто же.
1
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
17.11.2019, 12:32  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
а я бы немного изменил модель данных. Ввёл бы сущность "Адресат" и из сущности "Message" ссылался бы на неё. "Адресат" бы содержал коллекцию пользователей. Так, если в этой коллекции один пользователь - сообщение приватное, если несколько - то сообщение групповое. Таким образом чатик начнёт поддерживать комнаты \ группы как во всяких телеграммах\ватсапах\слаках и прочих подобных штуках.
как вариант для дальнейшего развития очень даже сносно, но т.к. у меня еще нет практически никакого опыта, я не могу понять, то, как решил сохранение сообщений, а затем и получение этих сообщений, правильно? Приемлемо ли так писать код, тут ведь все напролом у меня сейчас, я тупо создал модель сообщения и потом банально через ифы заполняю таблицы, и точно так же через ифы достаю инфу, смущает то, что при создании таблицы друзей я мучался с мани ту мани, в модель друзей добавлял навигационные поля, прописывал контекст бд, а тут тупо создал отдельную модель, внес ее в DbSet и все, никак не завязал ее с таблицей пользователей и заполняю и получаю данные путем сравнения через иф, это так вообще приемлемо?
0
Эксперт .NET
 Аватар для Usaga
14313 / 9393 / 1355
Регистрация: 21.01.2016
Сообщений: 35,425
18.11.2019, 07:21
Цитата Сообщение от Lucky64 Посмотреть сообщение
это так вообще приемлемо
Нет. Особенно вот это:

C#
1
2
3
4
5
6
7
8
9
10
11
12
            foreach (var i in db.Messages)
            {
                if(i.UserId==id && i.FriendId == FriendId)
                {
                    mesages.Add($"{username} {i.SentMessage}");
                    
                }
                else if (i.FriendId == id && i.UserId == FriendId)
                {
                    mesages.Add($"{friendname} {i.SentMessage}");
                }
            }
Здесь вы в оперативку вытаскиваете ВСЕ записи из базы. В мало-мальски популярном чатике записей сообщений может быть миллионы. Нужно указать EF'у какие именно записи вам нужно вытащить. А именно передать в метод Where() условия указанные в IF'ах.
1
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
18.11.2019, 11:09  [ТС]
Usaga, так, исправлю способ доставания, плс подскажите где еще проблемы? Если не сложно...
0
Эксперт .NET
 Аватар для Usaga
14313 / 9393 / 1355
Регистрация: 21.01.2016
Сообщений: 35,425
18.11.2019, 11:44
Lucky64, ещё из плохого: работа с контекстом EF'а прямо из контроллеров. Под два HttpGet атрибута на каждом методе контроллера (должен быть атрибут). В сущностях EF'а нет навигационных свойств. Та же болячка и в коде компонентов ангуляра: прямая работа с HttpClient прямо из самого компонента.
1
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
18.11.2019, 13:10  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
ещё из плохого: работа с контекстом EF'а прямо из контроллеров. Под два HttpGet атрибута на каждом методе контроллера (должен быть атрибут). В сущностях EF'а нет навигационных свойств. Та же болячка и в коде компонентов ангуляра: прямая работа с HttpClient прямо из самого компонента
таак, в компонентах клиента сделаю, в контроллерах еще не сталкивался с атрибутами, везде напрямую было... буду копать, спасибо!
0
Эксперт .NET
 Аватар для Usaga
14313 / 9393 / 1355
Регистрация: 21.01.2016
Сообщений: 35,425
18.11.2019, 13:36
Цитата Сообщение от Lucky64 Посмотреть сообщение
в контроллерах еще не сталкивался с атрибутами, везде напрямую было...
Я про это:

C#
1
2
3
[HttpGet("[action]/{id}"), Route("sevemessage")]
        [HttpGet("[action]/{id}/{friendid}"), Route("sevemessage")]
        public IActionResult GetMessages(int id, int FriendId)
Не хорошо это.

И то, что вы с EF голым работаете прямо в контроллерах - тоже. Вы такое могли на учебных примерах видеть. Это ОК. Это для простоты примеров делалось, а не потому, что это правильно.
1
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
18.11.2019, 16:05  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Я про это:
дада я понял, с клиентом разобрался и перенес все методы в датасервис, и уже через него использую методы в компонентах.
Цитата Сообщение от Usaga Посмотреть сообщение
И то, что вы с EF голым работаете прямо в контроллерах - тоже
плс подкинте пример как надо, я все перепишу и намотаю на ус так казать, а то везде так как я написал, а как работать не из контроллера, я не нашел, либо не заметил
Цитата Сообщение от Usaga Посмотреть сообщение
Я про это:
как мне забить в поисковик, чтобы наткнуться на инструкцию как правильно нужно?
спасибо заранее!!!
0
Эксперт .NET
 Аватар для Usaga
14313 / 9393 / 1355
Регистрация: 21.01.2016
Сообщений: 35,425
18.11.2019, 16:27
Цитата Сообщение от Lucky64 Посмотреть сообщение
дада я понял, с клиентом разобрался и перенес все методы в датасервис, и уже через него использую методы в компонентах.
Правильное решение.

Цитата Сообщение от Lucky64 Посмотреть сообщение
плс подкинте пример как надо, я все перепишу и намотаю на ус так казать, а то везде так как я написал, а как работать не из контроллера, я не нашел, либо не заметил
Точно так же, как вы на клиенте поступили: ввести сервисы работающие с определёнными сущностями и перенести всю возню с EF туда, а из контроллеров дёргать методы этих сервисов. В идеале: в каждом методе контроллера должен дёргаться только один метод одного сервиса.

Цитата Сообщение от Lucky64 Посмотреть сообщение
как мне забить в поисковик, чтобы наткнуться на инструкцию как правильно нужно?
По одному маршруту на метод действия. Опциональные параметры должны быть nullable. Или метод разделить на два, у каждого свой маршрут и метод с меньшим количеством параметров просто перевызывает метод с большим количеством со вставкой null в параметры, которых ему взять неоткуда.
1
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
19.11.2019, 08:23  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Здесь вы в оперативку вытаскиваете ВСЕ записи из базы. В мало-мальски популярном чатике записей сообщений может быть миллионы. Нужно указать EF'у какие именно записи вам нужно вытащить. А именно передать в метод Where() условия указанные в IF'ах.
вот так переписал метод:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var usermessages = db.Messages.Where(x => x.UserId == id)
                .Where(x => x.FriendId == FriendId)
                .Where(x=>x.UserId==FriendId)
                .Where(x=>x.FriendId==id)
                .ToList();
 
            foreach (var i in usermessages)
            {
                if(i.UserId==id && i.FriendId == FriendId)
                {
                    mesages.Add($"{username}: {i.SentMessage}");
                    
                }
                else if (i.FriendId == id && i.UserId == FriendId)
                {
                    mesages.Add($"{friendname}: {i.SentMessage}");
                }
            }
так годно?

Добавлено через 10 минут
Usaga, нет не годно, уже понял, работаю дальше

Добавлено через 17 минут
Вот так заработало:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var usermessages = db.Messages.Where(x => x.UserId == id || x.UserId == FriendId).ToList();
 
            foreach (var i in usermessages)
            {
                if (i.UserId == id && i.FriendId == FriendId)
                {
                    mesages.Add($"{username}: {i.SentMessage}");
 
                }
                else if (i.FriendId == id && i.UserId == FriendId)
                {
                    mesages.Add($"{friendname}: {i.SentMessage}");
                }
            }
0
Эксперт .NET
 Аватар для Usaga
14313 / 9393 / 1355
Регистрация: 21.01.2016
Сообщений: 35,425
19.11.2019, 08:35
Lucky64, условие в Where не правильное. Вам нужны сообщения между двумя конкретными пользователями. А вы выгребаете сообщения в которых фигурирует хотя бы один пользователь (из двух искомых), а потом в оперативке уже вытаскиваете сообщения конкретной пары пользователей. Это не правильно.

Добавлено через 6 минут
Lucky64, кстати, сортировки по дате поступления сообщений тоже нет. Видимо, идёт рассчёт на то, что порядок определяемый первичным ключом будет совпадать с порядком добавления сообщений в базу. Но это не всегда верно и не правильно на это завязываться.
1
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
19.11.2019, 08:50  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
условие в Where не правильное. Вам нужны сообщения между двумя конкретными пользователями. А вы выгребаете сообщения в которых фигурирует хотя бы один пользователь (из двух искомых), а потом в оперативке уже вытаскиваете сообщения конкретной пары пользователей. Это не правильно.
ага уже увидел ошибку добавив 3-го пользователя...
переписал вот так, и вроде все теперь работает как надо
C#
1
2
3
4
5
var usermessages = db.Messages.Where(x => x.UserId == id 
                && x.FriendId == FriendId 
                || x.UserId == FriendId 
                && x.FriendId == id)                
                .ToList();
если и так не верно, но даже не знаю как еще задать условия

Цитата Сообщение от Usaga Посмотреть сообщение
кстати, сортировки по дате поступления сообщений тоже нет. Видимо, идёт рассчёт на то, что порядок определяемый первичным ключом будет совпадать с порядком добавления сообщений в базу. Но это не всегда верно и не правильно на это завязываться.
добавлю значит
0
Эксперт .NET
 Аватар для Usaga
14313 / 9393 / 1355
Регистрация: 21.01.2016
Сообщений: 35,425
19.11.2019, 09:00
Lucky64,
C#
1
2
3
4
var usermessages = db.Messages
              .Where(x => (x.UserId == id && x.FriendId == FriendId) ||
                          (x.UserId == FriendId && x.FriendId == id))                
              .ToList();
0
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
19.11.2019, 09:16  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
var usermessages = db.Messages
              .Where(x => (x.UserId == id && x.FriendId == FriendId) ||
                          (x.UserId == FriendId && x.FriendId == id))                
              .ToList();
скобки...точно... спасибо!

Добавлено через 4 минуты
Usaga,
Добавил дату и время:
C#
1
2
3
4
5
6
7
8
public class Message
    {       
        public int Id { get; set; }
        public int UserId { get; set; }
        public int FriendId { get; set; }
        public string SentMessage { get; set; }
        public DateTime dateTime { get; set; }
    }
в методе отправляю дату сохранения сообщения
C#
1
2
db.Messages.Add(new Message { UserId = currentUser.Id, FriendId = recipient.Id, SentMessage = message, dateTime = DateTime.Now  });         
            db.SaveChanges();
удалил всю бд, удалил пакпку миграции, создал все по новой через add-migration, проверяю таблицы, в сообщениях все осталось как было, т.е. для даты и времени не создалось дополнительной ячейки, так и должно быть? просто раньше никогда еще не работал с датами...
0
 Аватар для Lucky64
20 / 9 / 0
Регистрация: 16.01.2019
Сообщений: 288
19.11.2019, 09:21  [ТС]
Хотя в чате все заработало
Миниатюры
Поместить переписку в БД  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.11.2019, 09:21
Помогаю со студенческими работами здесь

Реализовать внутреннюю переписку на сайте
Пытаюсь реализовать внутреннею переписку на сайте. Код реализовал, но проблема с mysql возникла..... Таблицу думаю неправильно состряпал....

Восстановить переписку в Outlook Express
В 2004 году загрузил Outlook Express и пользовался этой почтой до 2012 года. Потом продал ноутбук переехал. Здесь на компе Windows XP....

Как лучше хранить переписку?
В мускуле или текстовом файле? Хотя если переписку хранить в текстовом файле, то для навигации по переписке с определённым пользователем...

Как в яндекс почте удалить переписку
Здравствуйте, я в яндекс почте случайно письмо отправил не по правильному адресу, как можно удалить сообщение?

Как перевернуть переписку в HTML&
Я созранил перепискув ХТМЛ, и теперь мне надо отредактировать. Дело в том, что переписка читается не сверху вниз, а снизу вверх, то есть...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Отправка уведомления на почту при изменении наименования справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере изменения наименования справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной записи. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
Контроль уникальности заводского номера - вариант №2
Maks 24.03.2026
В отличие от предыдущего варианта добавлено прерывание циклов, также добавлены новые переменные для сохранения контекста ошибки перед прерыванием цикла: Процедура ПередЗаписью(Отказ, РежимЗаписи,. . .
SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++
8Observer8 24.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-text-sdl3-c. zip finish-text-sdl3-cpp. zip
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
Контроль уникальности заводского номера - вариант №1
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере документа выдачи шин для спецтехники с табличной частью в конфигурации КА2. Данные берутся из регистра сведений, по. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru