トークに関連付ける必要があるタグを使用して新しい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;
}
}
}
あなたのエンティティのプロパティは 'virtual'なので、ナビゲーションプロパティが正しく設定されていないようです。 – Eris
私は仮想エンティティについてはあまりよく分かりませんが、EFコアのドキュメント(https://docs.microsoft.com/en-us/ef/core/modeling/relationships)で多対多のガイドに従っています。 – Luca
あなたもTalkViewModelコードを提供する必要があります。あなたのコードを見ると、タグID、タグテキスト、ブール "Selected"プロパティを持つTalkViewModelのListプロパティが必要になると思います。次に、TalkViewModelをレポに渡すときに、選択したTagViewModelsをフィルタリングし、それぞれのトークンを適切なTagIdを付けてTalkTagプロパティに追加します。 EFはSaveChanges()に適切なTalkIdを追加する必要があります。 –