C
C#3y ago
İrşat

EF 6 - Creating entity with n-n

PostDtoWrite_2 newpost = new PostDtoWrite_2();
newpost.Title = request.Title;
newpost.PostDescription = request.PostDescription;
newpost.LanguageId = request.LanguageId;
newpost.AccountId = request.AccountId;
newpost.PostTypeId = request.PostTypeId;
newpost.CoverImage = request.CoverImage;
newpost.PublishDate = DateTime.Now;
newpost.UpdateDate = DateTime.Now;
newpost.DeletedStatusId = 1;
newpost.PostTypeId = 1;
newpost.IsPublished = true;

try{
db.Posts.Add(mapper.Map<Post>(newpost));
await db.SaveChangesAsync();
} catch (Exception) {
return Results.StatusCode(580);
}

return Results.Ok();
PostDtoWrite_2 newpost = new PostDtoWrite_2();
newpost.Title = request.Title;
newpost.PostDescription = request.PostDescription;
newpost.LanguageId = request.LanguageId;
newpost.AccountId = request.AccountId;
newpost.PostTypeId = request.PostTypeId;
newpost.CoverImage = request.CoverImage;
newpost.PublishDate = DateTime.Now;
newpost.UpdateDate = DateTime.Now;
newpost.DeletedStatusId = 1;
newpost.PostTypeId = 1;
newpost.IsPublished = true;

try{
db.Posts.Add(mapper.Map<Post>(newpost));
await db.SaveChangesAsync();
} catch (Exception) {
return Results.StatusCode(580);
}

return Results.Ok();
I want to add "Tags" to this but there is no table for many to many in new versions of EF.
48 Replies
İrşat
İrşatOP3y ago
public virtual ICollection<Tag> Tags { get; set; } I have this in my entity.
Angius
Angius3y ago
Collection of A in B, collection of B in A All that's needed And get rid of any and all virtual in your models
İrşat
İrşatOP3y ago
that's database first, i will delete the virtuals in dtos if there is one but i didn't understand a and b thing
Angius
Angius3y ago
Example model names
İrşat
İrşatOP3y ago
let me process it for a minute 😄
Brainiac V
Brainiac V3y ago
First result on Google:
The second most common type of relationship is known as a Many To Many relationship. The following diagram shows how this appears in a database diagram. Each book can belong to many categories and each category can contain many books. This type of relationship is managed in a database through the use of a join table (also known among other things as a bridging, junction or linking table). This type of relationship is defined in code by the inclusion of collection properties in each of the entities:
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
public ICollection<Category> Categories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public ICollection<Book> Books { get; set; }
}
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
public ICollection<Category> Categories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public ICollection<Book> Books { get; set; }
}
İrşat
İrşatOP3y ago
yeah i already knew that though. But how do I add the Tags, I tried filling this collection but it gave an error also i use mapper, maybe there is something about it too
Angius
Angius3y ago
book.Categories.Add(category);
await _ctx.SaveChangesAsync();
book.Categories.Add(category);
await _ctx.SaveChangesAsync();
İrşat
İrşatOP3y ago
oh
Angius
Angius3y ago
You need the actual model intances too, not mapped DTOs
İrşat
İrşatOP3y ago
but i am using dto, is there an other way
Angius
Angius3y ago
No
İrşat
İrşatOP3y ago
let me try this first thanks btw
Brainiac V
Brainiac V3y ago
You can see the flow like this: 1) Request comes from the client to get data: Model -> DTO 2) Client sends data that results in creating or updating something: DTO -> Model
İrşat
İrşatOP3y ago
2) yes i am using mapper for that db.Posts.Add(mapper.Map<Post>(newpost)); db.Posts.Tags Doesn't exists i guess
Angius
Angius3y ago
You don't have N-N set up, then
İrşat
İrşatOP3y ago
public virtual ICollection<Tag> Tags { get; set; } it's there
Angius
Angius3y ago
Ah You need a specific post Not all the posts
İrşat
İrşatOP3y ago
i get the tags, i just can't create them in n n table
Angius
Angius3y ago
Of course a DbSet of Posts won't contain a property Tags
var post = await _ctx.Posts.FindAsync(id);
post.Tags.Add(new Tag { ... });
await _ctx.SaveChangesAsync();
var post = await _ctx.Posts.FindAsync(id);
post.Tags.Add(new Tag { ... });
await _ctx.SaveChangesAsync();
İrşat
İrşatOP3y ago
so i was thinking i could get the newly created post's id and then add the tags into the n n table. But simply there is no table in ef core 6 😄 let me check what you wrote
Angius
Angius3y ago
You can add it to the newly-created post tho..?
İrşat
İrşatOP3y ago
I have Post table, Tags table and Post_Tag table. post.Tags.Add(new Tag { ... }); I don't think that would work
Angius
Angius3y ago
var post = new Post();
post.Tags = new List<Tag>(){
tag1, tag2, tag3
};
_ctx.Posts.Add(post);
await _ctx.SaveChangesAsync();
var post = new Post();
post.Tags = new List<Tag>(){
tag1, tag2, tag3
};
_ctx.Posts.Add(post);
await _ctx.SaveChangesAsync();
İrşat
İrşatOP3y ago
unless the "tags" here is the n n table here? oh i see but i tried this and got an error
Angius
Angius3y ago
Nothing here is the join table
Brainiac V
Brainiac V3y ago
I think you need to get away from that thinking in relations in databases for a moment
Angius
Angius3y ago
There's zero join tables C#-side
Brainiac V
Brainiac V3y ago
and switch to classes and objects
İrşat
İrşatOP3y ago
okay okay i just saw that part. I am just saying i tried this filling the property thing. Catch was triggered, but let me check the error first should i create ICollection or List? as property
Angius
Angius3y ago
List You cannot instantiate interfaces Ah, property? ICollection, List, either's fine
İrşat
İrşatOP3y ago
alright is giving id only fine? Tags has an id and body.
Angius
Angius3y ago
Ideally, you'd fetch the tags by ID from the database, but you can use an instance of Tag with ID alone, I think
İrşat
İrşatOP3y ago
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 64.
Angius
Angius3y ago
Ah, don't return database models from your API
İrşat
İrşatOP3y ago
public List<TagDtoWrite_1>? Tags { get; set; } i am not returning it 😄
Angius
Angius3y ago
Maybe because of the virtual? It enables lazy loading Dunno
İrşat
İrşatOP3y ago
this error is completely irrelevant lol
Angius
Angius3y ago
There's a cycle somewhere in what you return
İrşat
İrşatOP3y ago
oh maybe it was a different error, i saw it in the terminal. It says this; Cannot insert explicit value for identity column in table 'Tag' when IDENTITY_INSERT is set to OFF. i am not trying to create a tag am i 😄
Angius
Angius3y ago
Ah, when you're adding tags to the post, you do it with new Tag { Id = id } EF takes it as an attempt at creating a tag
İrşat
İrşatOP3y ago
i used swagger for that "tags": [ { "id": 1 }, { "id": 2 }, { "id": 3 } ]
Angius
Angius3y ago
So you either have to track those tags, to tell EF those are shims for existing ones, or you have to fetch the tags from the db
var tags = await _ctx.Tags
.Where(t => tagIds.Contains(t.Id))
.ToListAsync();

var post = new Post();
post.Tags = tags;

await _ctx.SaveChangesAsync();
var tags = await _ctx.Tags
.Where(t => tagIds.Contains(t.Id))
.ToListAsync();

var post = new Post();
post.Tags = tags;

await _ctx.SaveChangesAsync();
This would be the safest way Or... you can create an entity that represents the join table and configure it But I hear you use DB-first, so no clue how to do that I refuse to touch DB-first with a ten-foot pole
İrşat
İrşatOP3y ago
it's so fun so far, why tho code first sounds messy
Angius
Angius3y ago
It's the opposite, in my experience You write the code how you want it, define all the relationships as you need them, and never worry about the database At any and all times you work with C# There's no virtuals being generated, no BeanDto_5367s
İrşat
İrşatOP3y ago
i see, maybe i learn code first when this is over foreach (var t in request.Tags) { newpost.Tags.Add(t); } This add method gives null error. Maybe I can't get the Tags from swagger at all 😄 I will return in 5 minutes
Angius
Angius3y ago
Need to intialize the tags collection Or you can just do newpost.Tags = request.Tags
İrşat
İrşatOP3y ago
yup it was already like that, i tried your way to see if there will be a difference and I noticed the null error while it's nullable, foreach gave an error like that welp, i can return the data and it gives me all the tags. I don't know why it says it's null @Angius I remembered your advice about creating an entity instead of the dto. I don't know why I insisted about creating dto and mapping it. I am already getting the data as dto so there is no security risk or anything 😄 It worked, thanks.

Did you find this page helpful?