Entity Framework - Вставка модели с отображением «многие ко многим» - PullRequest
0 голосов
/ 30 декабря 2018

Как я могу вставить модель Tag, которая принадлежит модели Post, когда у меня есть такие настройки моделей:

Post

public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
    public Post()
    {
       Tags = new List<Tag>();
    }
}

Tag

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
}

В этом вопросе предлагается создать объект Post, а затем добавить теги в коллекцию Tags, у меня не получилось: Вставить / обновить многие в многиеEntity Framework.Как мне это сделать?

Я хочу добавить Tag to Post уже в базе данных, как я могу сделать это с EF.Я новичок в EF.

Это то, что я пробовал, если я отправляю это в API, он не вставляет никаких записей, и я вижу, что нового tag Id = 0, который не существуетв базе данных, но я думаю, что это приведет к ошибке ограничения внешнего ключа, не уверен Если мне нужно что-то сделать для автоматического создания идентификатора для тега:

{
    Name: "test"
}

API

[ResponseType(typeof(Tag))]
public IHttpActionResult PostTag(Tag tag)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var post = new Post();
    var tags = new List<Tag>();
    tags.Add(tag);

    post.Tags.Add(tag);
    post.Id = 10;
    db.Entry(post).State = EntityState.Modified;
    db.SaveChanges();

    return CreatedAtRoute("DefaultApi", new { id = tag.Id }, tag);
}

1 Ответ

0 голосов
/ 30 декабря 2018

Если вы сказали, что есть отношение Many-To-Many, которое PostTag является таблицей соединений между Tag и Post, то ваши модели не показывают никакого отношения many-to-many, поэтому из того, что я видел, есть one-to-many между Post и Tag из-за определения вашей модели.

если вы хотите установить many-to-many связь между ними, вы должны что-то вроде ниже:

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
    public Tag()
    {
        Posts = new HashSet<Post>();
    }
} 
public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Tag> Tags { get; set; } 
    public Post()
    {
        Tags = new HashSet<Tag>();
    }
}

ив OnModelCreating создайте связь по API, как показано ниже:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{ 
    modelBuilder.Entity<Tag>()
        .HasMany(s => s.Posts)
        .WithMany(c => c.Tags)
        .Map(cs =>
        {
            cs.MapLeftKey("TagId");//TagId
            cs.MapRightKey("PostId");//PostId
            cs.ToTable("PostTag");
        });
}

или наоборот

modelBuilder.Entity<Post>()
    .HasMany(s => s.Tags)
    .WithMany(c => c.Posts)
    .Map(cs =>
        {
            cs.MapLeftKey("PostId");//PostId
            cs.MapRightKey("TagId");//TagId
            cs.ToTable("PostTag");
        });

, как вы можете видеть и знать, что в базе данных должна быть таблица с именем PostTagкоторые имеют два столбца в качестве ключей и имеют скрипт типа:

CREATE TABLE [dbo].[PostTag](
    [TagId] [int] NOT NULL,
    [PostId] [int] NOT NULL,
 CONSTRAINT [PK_PostTag] PRIMARY KEY CLUSTERED 
(
    [TagId] ASC,
    [PostId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] 

ALTER TABLE [dbo].[PostTag]  WITH CHECK ADD  CONSTRAINT [FK_PostTag_Post] FOREIGN KEY([PostId])
REFERENCES [dbo].[Post] ([Id])
GO 
ALTER TABLE [dbo].[PostTag] CHECK CONSTRAINT [FK_PostTag_Post]
GO 
ALTER TABLE [dbo].[PostTag]  WITH CHECK ADD  CONSTRAINT [FK_PostTag_Tag] FOREIGN KEY([TagId])
REFERENCES [dbo].[Tag] ([TagId])
GO 
ALTER TABLE [dbo].[PostTag] CHECK CONSTRAINT [FK_PostTag_Tag]
GO

. Для получения дополнительной информации посмотрите здесь .

ОБНОВЛЕНИЕ:

если вы хотите установить zero-to-many отношение между Post и Tag, то модели должны быть такими, как показано ниже:

public class Tag
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? PostId { get; set; }
}
public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }
    public Post()
    {
        Tags = new HashSet<Tag>();
    }
}

и отношение один-ко-многим с текущими API:

modelBuilder.Entity<Post>()
   .HasMany(o1 => o1.Tags);

в качестве комментария вы не хотите, чтобы у Tag было свойство навигации, поэтому вы должны определить свойство как Nullable в Tagэто симметричный ключ, если между ними есть связь, вы должны установить связь хотя бы с помощью свойства navte или свойства Nullable.

Правильный ответ пришел от здесь (без изменений): если вы хотите присвоить тег существующему сообщению, вы должны сначала найти это сообщение, а затем добавить к нему тег, если этот тег существует в БД, между тегом и найденным сообщением будет установлена ​​связь, если этот тег делаетне существует, тег будет вставлен в БД,

Посмотрите на это:

var post = context.Posts.SingleOrDefault(x => x.Id == 4);//That Id would be you specific Post Id
var existTag = context.Tags.SingleOrDefault(x => x.Id == 1); //Exist Tag in DB
post.Tags.Add(existTag);
context.SaveChanges();
//Inserting new tag to DB and assign it to Post also
Tag newTag = new Tag // Does not exist in DataBase
{
    Name = "tag2"
};
post.Tags.Add(newTag);// By this tag2 will be insert into Tag table first and then added to post (insert new record to PostTag)
context.SaveChanges();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...