Модель:
using MySql.Data.EntityFrameworkCore.DataAnnotations;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace Messager.Models
{
[MySqlCharset("utf-8")]
public class Message
{
public int MessageId { get; set; }
[Column("Body")]
public string BodyMassage { get; set; }
//Время, когда отправлено
public DateTime TimeSend { get; set; }
//Время, когда принято
public DateTime TimeCame { get; set; }
//Время, когда прочитано
public DateTime TimeRead { get; set; }
[NotMapped]
public virtual IList<MessageCustomUser> MessageCustomUsers { get; set; }
}
public class CustomUser
{
public int CustomUserId { get; set; }
public string Login { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public virtual IList<MessageCustomUser> MessageCustomUsers { get; set; }
}
public class MessageCustomUser
{
public int MessageId { get; set; }
public Message Message { get; set; }
public int CustomUserId { get; set; }
public CustomUser CustomUser { get; set; }
}
}
контекст:
using Messager.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Messager.Data
{
public class dataContext : DbContext
{
public dataContext(DbContextOptions<dataContext> options) : base(options)
{
}
public DbSet<Message> Messages { get; set; }
public DbSet<CustomUser> CustomUsers { get; set; }
public DbSet<MessageCustomUser> MessageCustomUser { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MessageCustomUser>().HasKey(mcu => new { mcu.CustomUserId, mcu.MessageId });
modelBuilder.Entity<MessageCustomUser>()
.HasOne<CustomUser>(sc => sc.CustomUser)
.WithMany(s => s.MessageCustomUsers)
.HasForeignKey(sc => sc.CustomUserId);
modelBuilder.Entity<MessageCustomUser>()
.HasOne<Message>(sc => sc.Message)
.WithMany(s => s.MessageCustomUsers)
.HasForeignKey(sc => sc.MessageId);
}
}
}
действие:
return Ok(context.MessageCustomUser.Where(x => x.CustomUserId == 2).FirstOrDefault());
данные:
результат:
Никак не разберусь со связью в ef, почему свойства Message
и CustomUser
пустые
UPDATE
действие:
return Ok(context.MessageCustomUser.Where(x => x.CustomUserId == 2).Include(x => x.Message).FirstOrDefault());
по адресу About:
Тот же самый адрес в постмене:
Нашел проблему:
Получается когда я делаю var messages = context.CustomUsers.Include(dd => dd.MessageCustomUsers).ThenInclude( p => p.Message).ToList();
то все нормально. Просто не выводит messages
т к попадает в бесконечный цикл по ссылкам. Получается если я пишу так:
public ActionResult About()
{
//ViewData["Message"] = "Your application description page.";
var messages = context.CustomUsers.Include(dd => dd.MessageCustomUsers).ThenInclude( p => p.Message).ToList();
List<string> str_ = new List<string>();
foreach(var m in messages)
{
var mess = m.MessageCustomUsers.Select(qwe => qwe.Message).ToList();
foreach (var mm in mess)
{
str_.Add($"логин: {m.Login} Сообщение: {mm.BodyMassage}");
}
}
return Ok(str_);
}
то все выводит ок:
Вопрос: как сделать чтобы компилятор не скитался по ссылкам и вывести все messages
в полноценном виде (все поля пользователя и связанного с ним сообщения)?
Создаем контекст данных. Я взял ваш.
Модели:
[MySqlCharset("utf-8")]
public class Message
{
public int MessageId { get; set; }
[Column("Body")]
public string BodyMassage { get; set; }
//Время, когда отправлено
public DateTime TimeSend { get; set; }
//Время, когда принято
public DateTime TimeCame { get; set; }
//Время, когда прочитано
public DateTime TimeRead { get; set; }
[NotMapped]
public virtual IList<MessageCustomUser> MessageCustomUsers { get; set; }
}
public class CustomUser
{
public int CustomUserId { get; set; }
public string Login { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public virtual IList<MessageCustomUser> MessageCustomUsers { get; set; }
}
public class MessageCustomUser
{
public int MessageId { get; set; }
public Message Message { get; set; }
public int CustomUserId { get; set; }
public CustomUser CustomUser { get; set; }
}
Таблица MessageCustomUser нам нужна, так как EFCore не сильно дружит со связями many-to-many.
public class MyAppDbContext : DbContext
{
public MyAppDbContext(DbContextOptions<MyAppDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MessageCustomUser>().HasKey(mcu => new { mcu.CustomUserId, mcu.MessageId });
modelBuilder.Entity<MessageCustomUser>()
.HasOne<CustomUser>(sc => sc.CustomUser)
.WithMany(s => s.MessageCustomUsers)
.HasForeignKey(sc => sc.CustomUserId);
modelBuilder.Entity<MessageCustomUser>()
.HasOne<Message>(sc => sc.Message)
.WithMany(s => s.MessageCustomUsers)
.HasForeignKey(sc => sc.MessageId);
}
public DbSet<Message> Messages { get; set; }
public DbSet<CustomUser> CustomUsers { get; set; }
public DbSet<MessageCustomUser> MessageCustomUser { get; set; }
}
Далее, нам нужны модели для отдачи с контроллера. Не путайте объекты, что вы читаете из БД и объекты, что вы отдаете на клиент. Выглядят они так
public class CustomUserModel
{
public int CustomUserId { get; set; }
public string Login { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public List<MessageModel> Messages { get; set; }
}
public class MessageModel
{
public int MessageId { get; set; }
public string BodyMassage { get; set; }
//Время, когда отправлено
public DateTime TimeSend { get; set; }
//Время, когда принято
public DateTime TimeCame { get; set; }
//Время, когда прочитано
public DateTime TimeRead { get; set; }
}
Далее, в классе Startup
Конфиг для доступа к БД
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyAppDbContext>(options =>
options.UseMySql("server=localhost; database=sampledb; port=3306; user=root;"));
services.AddMvc();
// проблема с циклическими ссылками решается так, это если вы таки БД объекты решите сериализовать
// .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
Конфиг для контроллеров и маппинга (использую AutoMapper)
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}");
});
Mapper.Initialize(config =>
{
config.CreateMap<Message, MessageModel>();
config.CreateMap<CustomUser, CustomUserModel>()
.AfterMap((dbUser, model) =>
{
model.Messages = dbUser.MessageCustomUsers?
.Select(m => Mapper.Map<MessageModel>(m.Message))?
.ToList();
});
});
}
Пример контроллера
public class HomeController : Controller
{
MyAppDbContext _ctx;
public HomeController(MyAppDbContext ctx)
{
_ctx = ctx;
}
public async Task<IActionResult> Index()
{
return Ok(
(await _ctx.CustomUsers
.Include(x=>x.MessageCustomUsers)
.ThenInclude(x=>x.Message)
.ToArrayAsync())
.Select(c=>Mapper.Map<CustomUserModel>(c))
.ToArray());
}
}
После этого добавляем миграцию
dotnet ef migrations add initial
Обновляем БД
dotnet ef database update
Далее, открываем базу, накидываем данные, запускаем вебсайт
dotnet run
Идем поглядеть, что же там в контроллере
http://localhost:5000/home/index
Получаем на выходе
[
{
"customUserId": 1,
"login": "11",
"username": "222",
"email": "333",
"password": "444",
"messages": [
{
"messageId": 1,
"bodyMassage": "sfsdfsdf",
"timeSend": "2019-01-01T00:00:00",
"timeCame": "2019-01-01T00:00:00",
"timeRead": "2019-01-01T00:00:00"
},
{
"messageId": 2,
"bodyMassage": "sdfsdf",
"timeSend": "2019-01-01T00:00:00",
"timeCame": "2019-01-01T00:00:00",
"timeRead": "2019-01-01T00:00:00"
}
]
},
{
"customUserId": 2,
"login": "222",
"username": "444",
"email": "666",
"password": "777",
"messages": [
{
"messageId": 1,
"bodyMassage": "sfsdfsdf",
"timeSend": "2019-01-01T00:00:00",
"timeCame": "2019-01-01T00:00:00",
"timeRead": "2019-01-01T00:00:00"
},
{
"messageId": 2,
"bodyMassage": "sdfsdf",
"timeSend": "2019-01-01T00:00:00",
"timeCame": "2019-01-01T00:00:00",
"timeRead": "2019-01-01T00:00:00"
}
]
}
]
Виртуальный выделенный сервер (VDS) становится отличным выбором
Строю график, отражающий динамику прохождения тестов пользователемНа оси Y отражается коэффициент(результат), на Х - дата выполнения
Работаю в Wpf с библиотекой Live ChartsНужно обработать нажатие на квадрат,чтобы квадрат заполнился или поменял цвет! Достиг только того что при...