4

トークに関連付ける必要があるタグを使用して新しいTalkを作成するAPIエンドポイントを作成しています。私は、ドメイン内のタグと会話の間に多対多の関係を設定しています。その関係については以下を参照してください。Entity Frameworkで多対多の関係を話すタグを追加します

Tag.cs​​

using System; 
using System.Collections.Generic; 

namespace Conferency.Domain 
{ 
    public class Tag : IAuditable 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
     public List<TalkTag> TalkTags { get; set; } 
     public DateTime ModifiedAt { get; set; } 
     public DateTime CreatedAt { get; set; } 
    } 
} 

Talk.cs

using System; 
using System.Collections.Generic; 

namespace Conferency.Domain 
{ 
    public class Talk : IAuditable 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
     public string Url { get; set; } 
     public List<TalkTag> TalkTags { get; set; } 
     public DateTime Presented { get; set; } 
     public DateTime ModifiedAt { get; set; } 
     public DateTime CreatedAt { get; set; } 
    } 
} 

TalkTag.cs​​

using System; 
using System.Collections.Generic; 
using System.Text; 

namespace Conferency.Domain 
{ 
    public class TalkTag 
    { 
     public int TalkId { get; set; } 
     public Talk Talk { get; set; } 
     public int TagId { get; set; } 
     public Tag Tag { get; set; } 
    } 
} 

ConferencyContext.cs(削除無関係コード)

TalkViewModel.cs

using System; 
using System.Collections.Generic; 

namespace Conferency.Application.Models 
{ 
    public class TalkViewModel 
    { 
     public string Name { get; set; } 
     public string Url { get; set; } 
     public List<String> Tags { get; set; } 
    } 
} 

問題は、私が話とそのタグを(彼らが存在する場合、そうでない場合は作成し、添付)を作成する方法を見つけ出すことはできませんです。私はこれを達成するためにどのような順序で確実かはわかりません。タグが存在するかどうか、または使用できるfindOrCreateメソッドがあるかどうかを確認するために、各タグを照会する必要がありますか? Talkがまだ作成されていない場合、TalkTagレコードを作成するにはどうすればよいですか?私が理解していないこれを達成するための優雅な方法はありますか?

TalkRepository.cs

using System.Collections.Generic; 
using Conferency.Domain; 
using Microsoft.EntityFrameworkCore; 
using System; 
using System.Linq; 
using System.Threading.Tasks; 

namespace Conferency.Data 
{ 
    public class TalkRepository : ITalkRepository 
    { 
     private ConferencyContext _context; 

     public TalkRepository(ConferencyContext context) 
     { 
      _context = context; 
     } 

     public void Add(Talk entity) 
     { 
      _context.Add(entity); 
     } 

     public void AddWithTags(Talk entity, List<String> tags) 
     { 
      // Create Talk 
      // Query for each tag 
      // Create if they don't exist 
      // Attach to talk 
      // ?? 
     } 

     public IEnumerable<Talk> GetAllTalks() 
     { 
      return _context.Talks 
       .Include(c => c.TalkTags) 
       .OrderBy(c => c.Presented) 
       .ToList(); 
     } 

     public Talk GetTalk(int id) 
     { 
      return _context.Talks 
       .Include(c => c.TalkTags) 
       .Where(c => c.Id == id) 
       .FirstOrDefault(); 
     } 

     public async Task<bool> SaveAllAsync() 
     { 
      return (await _context.SaveChangesAsync()) > 0; 
     } 
    } 
} 

私はC#に新しいですし、私はベストプラクティスを学び、EFおよびASP.NETコアで自分を習熟するので、うまくいけば、誰かが正しい道に私を導くことができますしようとしています。あなたが見てhttps://github.com/bliitzkrieg/Conferency

を取りたい場合は、完全な解決策はここにある私自身がそれを解決するが、イムは、NullPointerExceptionが取得しようとした、ここに私の解決策の試みです:

TalksController.csは

[HttpPost()] 
     public async Task<IActionResult> Post([FromBody]TalkViewModel model) 
     { 
      try 
      { 
       _logger.LogInformation("Creating a new Talk"); 

       List<Tag> tags = _tagRepo.FindOrCreateTags(model.Tags); 

       Talk talk = new Talk { Name = model.Name, Url = model.Url }; 

       List<TalkTag> talkTags = new List<TalkTag>(); 
       tags.ForEach(tag => 
       { 
        var talkTag = new TalkTag { TagId = tag.Id, Talk = talk }; 
        talkTags.Add(talkTag); 
       }); 

       talk.TalkTags.AddRange(talkTags); // Exception being thrown here 
       _repo.Add(talk); 

       if (await _repo.SaveAllAsync()) 
       { 
        string newUri = Url.Link("TalkGet", new { id = talk.Id }); 
        return Created(newUri, talk); 
       } 
       else 
       { 
        _logger.LogWarning("Could not save Talk"); 
       } 
      } 
      catch (Exception ex) 
      { 
       _logger.LogError($"Threw exception while saving Talk: {ex}"); 
      } 

      return BadRequest(); 
     } 
    } 

TagRepository.csあなたTalkViewModel

using System; 
using System.Collections.Generic; 
using Conferency.Domain; 
using System.Threading.Tasks; 
using Microsoft.EntityFrameworkCore; 
using System.Linq; 

namespace Conferency.Data 
{ 
    public class TagRepository: ITagRepository 
    { 
     private ConferencyContext _context; 

     public TagRepository(ConferencyContext context) 
     { 
      _context = context; 
     } 

     public void Add(Tag entity) 
     { 
      _context.Add(entity); 
     } 

     public List<Tag> FindOrCreateTags(List<string> tags) 
     { 
      List<Tag> _tags = new List<Tag>(); 
      tags.ForEach(t => 
      { 
       try 
       { 
        var tag = _context.Tags 
         .Where(c => c.Name == t) 
         .FirstOrDefault(); 

        if (tag != null) 
        { 
         _tags.Add(tag); 
        } 
        else 
        { 
         Tag created = new Tag { Name = t }; 
         this.Add(created); 
         _tags.Add(created); 
        } 
       } 
       catch (Exception ex) 
       { 

       } 

      }); 

      return _tags; 
     } 

     public async Task<bool> SaveAllAsync() 
     { 
      return (await _context.SaveChangesAsync()) > 0; 
     } 
    } 
} 
+0

あなたのエンティティのプロパティは 'virtual'なので、ナビゲーションプロパティが正しく設定されていないようです。 – Eris

+0

私は仮想エンティティについてはあまりよく分かりませんが、EFコアのドキュメント(https://docs.microsoft.com/en-us/ef/core/modeling/relationships)で多対多のガイドに従っています。 – Luca

+0

あなたもTalkViewModelコードを提供する必要があります。あなたのコードを見ると、タグID、タグテキスト、ブール "Selected"プロパティを持つTalkViewModelのList プロパティが必要になると思います。次に、TalkViewModelをレポに渡すときに、選択したTagViewModelsをフィルタリングし、それぞれのトークンを適切なTagIdを付けてTalkTagプロパティに追加します。 EFはSaveChanges()に適切なTalkIdを追加する必要があります。 –

答えて

2

次のプロパティを持つList<TagViewModel>プロパティを追加:

public int TagId { get; set; } 
public string TagName { get; set; } 
public bool Selected { get; set; } 

あなたのレポにTalkViewModelを渡すと、選択したTagViewModel Sをフィルタリングし、それぞれについて、あなたのTalk上ごTalkTagsプロパティに適切なTagIdTalkTagを追加します。 EFは_context.SaveChanges()に適切なTalkIdを追加して世話をするべきです。

Tagは、あなたの_contextに追加し、そのプロパティなどの新しいTagと新しいTalkTalkTagを作成し、存在しない場合。 EFは残りを世話するべきです。

0

あなたはnullpointerを引き起こすTalkTagsコレクションを初期化していません。Talkオブジェクトを初期化するときにこれを試してください:

Talk talk = new Talk { Name = model.Name, Url = model.Url, TalkTags = new List<TalkTag>() }; 

TalkTagオブジェクトでさらにプロパティが必要ですか?そうでなければ、TagクラスにはList<Talk>、TalkクラスにはList<Tag>があり、マッピングはEFによって行われます(TalkTagテーブルがDBに作成されます)。

Michael Tranchidaはすでに、オブジェクトをコンテキストに追加する方法について説明しました。

関連する問題