I've created model named Level and now I'm trying to use Seed method to fill a database. Here's a model:
public class Level
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid LevelId { get; set; }
public string Name { get; set; }
[ForeignKey("Course")]
public Guid CourseId { get; set; }
public virtual Course Course { get; set; }
public virtual List<Stage> Stages { get; set; }
}
And here's a piece of Seed method
context.Courses.AddOrUpdate(
c => c.Name,
new Course() { Name = "C# for beginners", LanguageId = context.Languages.FirstOrDefault(k => k.Name == "C#").LanguageId, UserId = context.Users.FirstOrDefault(u => u.Login == "user1").UserId },
new Course() { Name = "Advanced C++", LanguageId = context.Languages.FirstOrDefault(k => k.Name == "C++").LanguageId, UserId = context.Users.FirstOrDefault(u => u.Login == "user2").UserId }
);
context.Levels.AddOrUpdate(
l => l.Name,
new Level() { Name = "Level 1", CourseId = context.Courses.FirstOrDefault(d => d.Name == "C# for beginners").CourseId },
new Level() { Name = "Level 2", CourseId = context.Courses.FirstOrDefault(d => d.Name == "C# for beginners").CourseId },
new Level() { Name = "Level 1", CourseId = context.Courses.FirstOrDefault(d => d.Name == "Advanced C++").CourseId }
);
I have a lot of problems with Levels. One time I had only 2 objects in database instead of 3, now I have
Sequence contains more than one element
error and I don't know why, few minutes ago I've updated database and everything was ok. What's wrong with it?
Thank you
Related
I am assigned the implementation of a REST GET with a complex DB model and somewhat complex output layout. Although I am a REST beginner, I have lost "rest" on this for 2 weeks spinning my wheels, and Google was of no help as well.
Here's a simplification of the existing DB I am given to work with:
Table group : {
Column id Guid
Column name string
Primary key: {id}
}
Table account
{
Column id Guid
Column name string
Primary key: {id}
}
Table groupGroupMembership
{
Column parentGroupId Guid
Column childGroupId Guid
Primary key: {parentGroupId, childGroupId}
}
Table accountGroupMembership
{
Column parentGroupId Guid
Column childAccountId Guid
Primary key: {parentGroupId, childAccountId}
}
So clearly you guessed it: There is a many-to-many relationship between parent a child groups. Hence a group can have many parent and child groups. Similarly, an account can have many parent groups.
The DB model I came up with in C# (in namespace DBAccess.Models.Tables):
public class Group
{
// properties
public Guid id { get; set; }
public string? name { get; set; }
// navigation properties
public List<GroupMemberAccount>? childAccounts { get; set; }
public List<GroupMemberGroup>? childGroups { get; set; }
public List<GroupMemberGroup>? parentGroups { get; set; }
}
public class Account
{
// properties
public Guid id { get; set; }
public string? name { get; set; }
// navigation properties
public List<GroupMemberAccount>? parentGroups { get; set; }
}
public class GroupMemberAccount
{
// properties
public Guid parentGroupId { get; set; }
public Guid childAccountId { get; set; }
//navigation properties
public Group? parentGroup { get; set; }
public Account? childAccount { get; set; }
static internal void OnModelCreating( EntityTypeBuilder<GroupMemberAccount> modelBuilder )
{
modelBuilder.HasKey(gma => new { gma.parentGroupId, gma.childAccountId });
modelBuilder
.HasOne(gma => gma.parentGroup)
.WithMany(g => g.childAccounts)
.HasForeignKey(gma => gma.parentGroupId);
modelBuilder
.HasOne(gma => gma.childAccount)
.WithMany(a => a.parentGroups)
.HasForeignKey(gma => gma.childAccountId);
}
}
public class GroupMemberGroup
{
// properties
public Guid parentGroupId { get; set; }
public Guid childGroupId { get; set; }
//navigation properties
public Group? parentGroup { get; set; }
public Group? childGroup { get; set; }
static internal void OnModelCreating(EntityTypeBuilder<GroupMemberGroup> modelBuilder)
{
modelBuilder.HasKey(gmg => new { gmg.parentGroupId, gmg.childGroupId });
modelBuilder
.HasOne(gmg => gmg.parentGroup)
.WithMany(g => g.childGroups)
.HasForeignKey(gmg => gmg.parentGroupId);
modelBuilder
.HasOne(gmg => gmg.childGroup)
.WithMany(g => g.parentGroups)
.HasForeignKey(gmg => gmg.childGroupId);
}
}
The corresponding DTO model I created:
public class Account
{
public Guid id { get; set; }
public string? name { get; set; }
public List<GroupMemberAccount>? parentGroups { get; set; }
}
public class AccountMappingProfile : AutoMapper.Profile
{
public AccountMappingProfile()
{
CreateMap<DBAccess.Models.Tables.Account, Account>();
}
}
public class Group
{
public Guid id { get; set; }
public string? Name { get; set; }
public GroupChildren children { get; set; } = null!;
};
public class GroupChildren
{
public List<GroupMemberAccount>? childAccounts { get; set; } = null!;
public List<GroupMemberGroup>? childGroups { get; set; } = null!;
}
public class GroupMemberAccount
{
public Guid parentGroupId { get; set; }
public Guid childAccountId { get; set; }
//public Group? parentgroup { get; set; } // commented out because no need to output in a GET request
public Account? childAccount { get; set; }
}
public class GroupMemberGroup
{
public Guid parentGroupid { get; set; }
public Guid childGroupId { get; set; }
//public Group? parentGroup { get; set; }; // commented out because no need to output in a GET request
public Group? childGroup { get; set; };
}
What you need to spot here is the difference in classes Group between the DB and DTO models.
In the DB model, Group has 3 lists: childAccounts, childGroups and parentGroups.
In the DTO model, Group has 1 node children of type GroupChildren which is a class that contains 2 of those 3 lists.
Hence an additional difficulty when it comes to design the mapping. That difference is intentional because it matches the following desired output for an endpoint such as: GET .../api/rest/group({some group guid}) is something like:
{
"id": "some group guid",
"name": "some group name",
"children": {
"childAccounts":{
"account":{ "name": "some account name 1"}
"account":{ "name": "some account name 2"}
...
}
"childFroups":{
"group":{ "name": "some group name 1"}
"group":{ "name": "some group name 2"}
...
}
},
}
obtained from following typical controller code:
[HttpGet("Groups({key})")]
[ApiConventionMethod(typeof(ApiConventions),
nameof(ApiConventions.GetWithKey))]
public async Task<ActionResult<Group>> Get(Guid key, ODataQueryOptions<Group> options)
{
var g = await (await context.Group.Include(g => g.childAccounts)
.Include(g => g.childGroups)
.Where(g => g.id == key)
.GetQueryAsync(mapper, options) // note the mapper here is the mapping defined below
).FirstOrDefaultAsync();
if (g is null)
{
return ResourceNotFound();
}
return Ok(g);
}
So here's the missing part to all this. Unless there are major errors in all of the above, I have a very strong intuition that it is the mapping that is failing to get me the requested output above.
public class GroupMappingProfile : AutoMapper.Profile
{
public GroupMappingProfile()
{
// the rather straightforward.
CreateMap<DBAccess.Models.Tables.GroupMemberAccount, GroupMemberAccount>();
CreateMap<DBAccess.Models.Tables.GroupMemberGroup, GroupMemberGroup>();
//Attempt 1: the not so straightforward. An explicit exhaustive mapping of everything, down to every single primitive type
CreateMap<DBAccess.Models.Tables.Group, Group>()
.ForMember(g => g.children, opts => opts.MapFrom(src => new GroupMembers
{
childAccounts = src.childAccounts!.Select(x => new GroupMemberAccount { parentGroupId = x.parentGroupId,
childAccountId = x.childAccountId,
childAccount = new Account { id = x.childAccount!.id,
name = x.childAccount!.name
}
}
).ToList(),
//childGroups = src.childGroups!.Select(x => new GroupMemberGroup(x)).ToList(),
childGroups = src.childGroups!.Select(x => new GroupMemberGroup { parentGroupId = x.parentGroupId,
childGroupId = x.childGroupId,
childGroup = new Group { id = x.childGroup!.id,
name = x.childGroup!.name
}
}
).ToList(),
}));
//Attempt 2: mapper injection
IMapper mapper = null!;
CreateMap<DBAccess.Models.Tables.Group, Group>()
.BeforeMap((_, _, context) => mapper = (IMapper)context.Items["mapper"]) //ADDING THIS LINE CAUSES ALL QUERIES TO LOOK FOR A NON EXISTENT Group.Groupid column
.ForMember(g => g.children, opts => opts.MapFrom(src => new GroupMembers
{
childAccounts = mapper.Map<List<DBAccess.Models.Tables.GroupMemberAccount>, List<GroupMemberAccount>>(src.childAccounts!),
childGroups = mapper.Map<List<DBAccess.Models.Tables.GroupMemberGroup>, List<GroupMemberGroup>>(src.childGroups!)
}))
}
}
Attempt1 will yield:
{
"id": "some guid",
"name": "some name"
"children": {}
}
even though the generated SQL does fetch all the required data to fill "children"
Attempt2 (mapper injection) is a technique I was suggested and have no clue how it is supposed to work. From what I gather, the mapping functions creates a few maps for some basic types while it uses its "future" self to create the remaining mappings, whenever it will be invoked in the future. Looks somehow like a one-time recursion.
However, it crashes as the generated SQL will look for a non-existent view column group.Groupid
SELECT [t].[id], [t].[name],
[g0].[parentGroupId], [g0].[childAccountId],
[g1].[parentGroupId], [g1].[childGroupId], [g1].[Groupid] -- where does [g1].[Groupid] come from??
FROM (
SELECT TOP(1) [g].[id], [g].[name]
FROM [HID_Rest].[group] AS [g]
WHERE [g].[id] = #__key_0
) AS [t]
LEFT JOIN [HID_Rest].[groupMemberAccount] AS [g0] ON [t].[id] = [g0].[parentGroupId]
LEFT JOIN [HID_Rest].[groupMemberGroup] AS [g1] ON [t].[id] = [g1].[parentGroupId]
ORDER BY ...
So regardless of the mapping profile I experimented with, what is the right mapping profile I need (and what ever else) to get the expected JSON output above? Or is this desired JSON structure possible at all?
After further work, I have figured that there was nothing wrong with my models and mapping. There's still something wrong though as the output to my GET requests is still incomplete. Here's the current new issue I need to deal with to solve this problem:
Issue with REST controller function Microsoft.AspNetCore.Mvc.ControllerBase.OK()?
I have current setup, with a Select indexer-projection (entity, index) (see SubRubrics). If i leave the indexer out, the problem is solved... However if I leave out the SubRubricItems then I can use the indexer. Is it only on the last select projection I can use it, or..?
Below linq projection, error message and more info.
await _db
.Exams
.AsNoTracking()
.Include(exam => exam.Stations)
.ThenInclude(station => station.Rubrics)
.ThenInclude(rubric => rubric.SubRubrics)
.ThenInclude(subRubric => subRubric.Items)
.Select(exam => new Result.ExamViewModel
{
Id = exam.Id,
Name = exam.Name,
Stations = exam.Stations.Select(station => new Result.StationViewModel
{
Id = station.Id,
Description = station.Description,
Rubrics = station.Rubrics.Select(rubric => new Result.RubricViewModel
{
Id = rubric.Id,
Name = rubric.Name,
Info = rubric.Info,
SubRubrics = rubric.SubRubrics.Select((subRubric, index) => new Result.SubRubricViewModel
{
Id = subRubric.Id,
Order = index,
Name = subRubric.Name,
Info = subRubric.Info,
Type = subRubric.Type.ToString(),
Items = subRubric.Items.Select(item => new Result.SubRubricItemViewModel
{
Id = item.Id,
Name = item.Name
})
})
})
})
})
.ToListAsync()
This provides this error which I don't understand :/
InvalidOperationException: Processing of the LINQ expression '(MaterializeCollectionNavigation(
navigation: Navigation: Rubric.SubRubrics,
subquery: (NavigationExpansionExpression
Source: DbSet<SubRubric>
.Where(s0 => !(s0.IsDeleted))
.Where(s0 => EF.Property<Nullable<long>>(r, "Id") != null && EF.Property<Nullable<long>>(r, "Id") == EF.Property<Nullable<long>>(s0, "RubricId"))
PendingSelector: s0 => (NavigationTreeExpression
Value: (EntityReference: SubRubric | IncludePaths: Items)
Expression: s0)
)
.Where(i => EF.Property<Nullable<long>>((NavigationTreeExpression
Value: (EntityReference: Rubric | IncludePaths: Version SubRubrics->...)
Expression: r), "Id") != null && EF.Property<Nullable<long>>((NavigationTreeExpression
Value: (EntityReference: Rubric | IncludePaths: Version SubRubrics->...)
Expression: r), "Id") == EF.Property<Nullable<long>>(i, "RubricId")))
.AsQueryable()
.Select((subRubric, index) => new SubRubricViewModel{
Id = subRubric.Id,
Order = index,
Name = subRubric.Name,
Info = subRubric.Info,
Type = subRubric.Type.ToString(),
Items = subRubric.Items
.AsQueryable()
.Select(item => new SubRubricItemViewModel{
Id = item.Id,
Name = item.Name
}
)
}
)' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.
This used to work, until I added the extra SubRubricItems select for the Items model, aka
Items = subRubric.Items.Select(item => new Result.SubRubricItemViewModel
{
Id = item.Id,
Name = item.Name
})
For reference sake, this is the viewmodel that's being projected into:
public sealed class Result
{
public IEnumerable<ExamViewModel> Exams { get; set; }
public sealed class ExamViewModel
{
public long Id { get; set; }
public string Name { get; set; }
public IEnumerable<StationViewModel> Stations { get; set; }
}
public sealed class StationViewModel
{
public long Id { get; set; }
public string Description { get; set; }
public IEnumerable<RubricViewModel> Rubrics { get; set; }
}
public sealed class RubricViewModel
{
public long Id { get; set; }
public string Name { get; set; }
public string Info { get; set; }
public IEnumerable<SubRubricViewModel> SubRubrics { get; set; }
}
public sealed class SubRubricViewModel
{
public long Id { get; set; }
public int Order { get; set; }
public string Name { get; set; }
public string Info { get; set; }
public string Type { get; set; }
public IEnumerable<SubRubricItemViewModel> Items { get; set; }
}
public sealed class SubRubricItemViewModel
{
public long Id { get; set; }
public int Order { get; set; }
public string Name { get; set; }
public string Info { get; set; }
public string Type { get; set; }
}
}
That can't be translated to SQL. So either run the SQL query before the .Select(),
.ThenInclude(subRubric => subRubric.Items)
.AsEnumerable()
.Select(exam => new Result.ExamViewModel
or remove the Includes (they don't do anything when you have a custom projection, and thereby change the query)
SubRubrics = rubric.SubRubrics.Select((subRubric) => new Result.SubRubricViewModel
{
Id = subRubric.Id,
Order = 0, . . .
and fill in the Order property on the view models afterwards.
I have a many-to-many relation in my Entity Framework context.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public IList<UserRole> UserRoles { get; set; }
}
public class UserRole
{
public int UserId { get; set; }
public int RoleId { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public IList<UserRole> UserRoles { get; set; }
}
And my context is:
public class MyContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserRole>().HasKey(sc => new { sc.UserId, sc.RoleId });
}
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
}
So when a user is assigned to a role, the record is in UserRole table. My roles table has 4 rows of data:
[
{ roleId = 1, name = "Administrator" },
{ roleId = 2, name = "Editor"},
{ roleId = 3, name = "x"},
{ roleId = 4, name = "y"}
]
But I want to select all roles for a user. But user assigned data property should be true like the following. For example I want to select roles for userid = 1. Because 2 role assigned.
roles = [
{ roleId = 1, name = "Administrator", isAddigned = true },
{ roleId = 2, name = "Editor", isAddigned = true },
{ roleId = 3, name = "x", isAddigned = false },
{ roleId = 4, name = "y", isAddigned = false }
]
Bot how can I select this query using Entity Framework?
From what it sounds like you have a user (ID #1) that has 2 roles currently assigned, Administrator and Editor. You want to list all available roles with a flag for "Is Assigned" set to True if the user has that role assignment, False if they do not.
To start, you likely do not need a UserRoles DbSet in your context. It's advisable to only create DbSets for entities that are considered top level entities (stuff you'll query) and rely on relationships to manage the rest.
If your goal is to return a list of Roles to associate to a user with an indicator of whether a user holds them or not (such as for a role assignment screen).
If you maintain UserRoles on the Role:
var roles = context.Roles
.Select(x => new RoleViewModel
{
RoleId = x.RoleId,
Name = x.Name,
IsAssigned = x.UserRoles.Any(ur => ur.UserId == userId)
}).ToList();
return roles;
When faced with a single-direction association (I.e. User contains UserRoles, but Roles does not) A simple first step would be to get the User's assigned role IDs, then use that as check against the complete list of roles. It requires 2 simple queries.
var usersRoleIds = context.Users
.Where(x => x.UserId == userId)
.SelectMany(x => x.UserRoles.Select(ur => RoleId))
.ToList();
var roles = context.Roles
.Select(x => new RoleViewModel
{
RoleId = x.RoleId,
Name = x.Name,
IsAssigned = userRoleIds.Contains(x.RoleId)
}).ToList();
return roles;
I am new to Entity Framework and I am hoping for some help to insert data in a "joined table".
I have three tables, Profiles, Tags and one called ProfilesTags that joins these two tables. Classes are autogenerated from database / DB First.
public partial class Profiles
{
public Profiles()
{
this.ProfilesTags = new HashSet<ProfilesTags>();
}
public int ProfileId { get; set; }
public string Name { get; set; }
...
public virtual ICollection<ProfilesTags> ProfilesTags { get; set; }
}
public partial class Tags
{
public Tags()
{
this.ProfilesTags = new HashSet<ProfilesTags>();
}
public int TagId { get; set; }
public string Tag { get; set; }
public virtual ICollection<ProfilesTags> ProfilesTags { get; set; }
}
public partial class ProfilesTags
{
public int Id { get; set; }
public int ProfileId { get; set; }
public int TagId { get; set; }
public virtual Tags Tags { get; set; }
public virtual Profiles Profiles { get; set; }
}
I have a SaveTags method that looks like this:
public void SaveTags(int profileId, IEnumerable<TagsNameValue> tags)
{
var pr = Context.Profiles.First(p => p.ProfileId == profileId);
// remove any existing
pr.ProfilesTags.Clear();
if (tags == null || !tags.Any())
return;
var ids = tags.Select(value => value.Value);
var names = tags.Select(value => value.Name);
// get a list of tags for lookup from [Tags]-table
var tagsList = Context.Tags.Where(t => ids.Any(v => t.TagId == v) || names.Any(v => t.Tag == v)).ToList();
foreach (var nameValue in tags)
{
var tag = tagsList.FirstOrDefault(t => t.TagId == nameValue.Value || t.Tag.ToLower() == nameValue.Name.ToLower());
// Tag is already in [Tags], no need to recreate id, just associate it.
if (tag != null)
{
var tagModel = new ProfilesTags()
{
TagId = nameValue.Value,
ProfileId = profileId
};
pr.ProfilesTags.Add(tagModel);
}
// create new item in [Tags] table first and add association [ProfilesTags]
else
{
var newTag = new Tags { Tag = nameValue.Name};
// how do I associate this newly added tag to pr.ProfilesTags ?
// what to do / how to procede?
Context.Tags.Add(newTag);
}
}
Context.SaveChanges()
}
How can I associate newTag with pr.ProfilesTags?
It seems newTag should have a valid id first, then build the relationship by ProfilesTags later.
// create new item in [Tags] table first and add association [ProfilesTags]
else
{
var newTag = new Tags { Tag = nameValue.Name};
// how do I associate this newly added tag to pr.ProfilesTags ?
// what to do / how to procede?
Context.Tags.Add(newTag);
// Let newTag has a valid tagId
Context.SaveChanges();
// Build the relationship between `Profiles` and `Tags`.
var newProfileTag = new ProfilesTags();
/// Build the relationship by ForeignKey,
/// Or, call pr.ProfilesTags.Add(newProfileTag)
newProfileTag.ProfiledId = pr.ProfileId;
newProfileTag.TagId = newTag.TagId; //< It SHOULD NOT be zero...
Context.ProfilesTags.Add(newProfileTag);
// Save the newProfileTag.....
// Context.SaveChanges();
}
I'm trying to seed some database tables that have a one to many relationship. Using the code first approach with the Entity Framework. Somehow the foreign keys remain empty in the database table activities, column UserId.
Why isn't this working?
context.Users.AddOrUpdate(
u => u.FirstName,
new User { Id = 1, FirstName = "Trees", Preposition = "de", LastName = "Vries", EmailAddress = "trees#test.com", PhoneNumber = 0684637485, Password = "test123", RoleId = 1 }
);
context.SaveChanges();
context.Activities.AddOrUpdate(
a => a.Name,
new Activity
{
Name = "Metselen van de binnenplaats",
Comment = "Voorbeeld commentaar regel 1.",
Start = DateTime.Now,
End = DateTime.Now.AddHours(5),
},//etc.
);
context.SaveChanges();
var randomActivities = (from s in context.Activities select s).OrderBy(x => Guid.NewGuid()).Take(6).ToList();
context.Users.AddOrUpdate(
u => u.Id,
new User { Id = 1, Activities = randomActivities }
);
context.SaveChanges();
Edit: Solution
After a few hours of wrestling with the code I finally managed to get it all working (without having to add foreign keys to the model classes).
I will share the code and some discoveries so others might benefit from it.
A few things to keep in mind.
Code directly to the context!
This does not work:
List<Activity> randomActivities = (from s in context.Activities select s).OrderBy(x => Guid.NewGuid()).Take(2).ToList(); //Does not work
Works:
List<Activity> randomActivities = context.Activities.OrderBy(x => Guid.NewGuid()).Take(2).ToList();
Only call SaveChanges() when you need to link objects that already need to be in the tables.
context.SaveChanges();
And Finally, you can create the data with a relationship to other tables, simple by adding a new List into it (see code below for details).
The seed method looks like this now:
var users = new List<User>
{
new User
{
FirstName = "Trees",
Preposition = "de",
LastName = "Vries",
EmailAddress = "trees#test.com",
PhoneNumber = 0684637485,
Password = "test123",
Activities =
new List<Activity> { // <-- Like this!
new Activity { Name = "Boren muren in de grote hal 1", Start = DateTime.Now, End = DateTime.Now.AddHours(5) },
new Activity { Name = "Vloer schuren 1", Start = DateTime.Now, End = DateTime.Now.AddHours(1) },
new Activity { Name = "Boren muren in de grote hal 2", Start = DateTime.Now, End = DateTime.Now.AddHours(5) },
new Activity { Name = "Vloer schuren 2", Start = DateTime.Now, End = DateTime.Now.AddHours(1) }
},
Messages =
new List<Message>
{
new Message { Subject = "Test onderwerp van bericht 1", Body = "Tekst van het bericht 1", AuthorId = 3 },
new Message { Subject = "Test onderwerp van bericht 2", Body = "Tekst van het bericht 2", AuthorId = 3 },
new Message { Subject = "Test onderwerp van bericht 3", Body = "Tekst van het bericht 3", AuthorId = 3 }
}
},
new User { FirstName = "Jaap", LastName = "Winter", EmailAddress = "jaap#test.com", PhoneNumber = 0628305643, Password = "test123" },
new User { FirstName = "Klaas", LastName = "Janssen", EmailAddress = "klaas#test.com", PhoneNumber = 0639453321, Password = "test123" }
};
users.ForEach(s => context.Users.AddOrUpdate(r => r.FirstName, s));
context.SaveChanges();
List<Activity> randomActivities = context.Activities.OrderBy(x => Guid.NewGuid()).Take(2).ToList();
var projects = new List<Project>
{
new Project { Name = "Test project", Description = "Omschrijving van test project 1.", Start = DateTime.Now, End = DateTime.Now.AddDays(10), User = context.Users.Single(s => s.FirstName == "Trees"), Activities = randomActivities }
};
projects.ForEach(s => context.Projects.AddOrUpdate(r => r.Name, s));
Activity model class:
public class Activity
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public Skill Skill { get; set; }
public string Comment { get; set; }
}
User model class:
public int Id { get; set; }
public string FirstName { get; set; }
public string Preposition { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public int PhoneNumber { get; set; }
public string Password { get; set; }
public bool Active { get; set; }
public Role Role { get; set; }
public ICollection<Skill> Skills { get; set; }
public ICollection<Message> Messages { get; set; }
public ICollection<Activity> Activities { get; set; }
}