これらのモデルをEF7で表現することはできますか?

c# entity-framework-core

質問

EF7を使用して永続化できるエンティティとして、自分のプロジェクトで別のアセンブリのクラスを使用しようとしています。データベースに優しい一連の非常によく似たクラスを記述するのではなく、

簡略化されたバージョンは次のようになります。

interface IMediaFile
{
    string Uri { get; }
    string Title { get; set; }
}
class CMediaFile : IMediaFile
{
    public CMediaFile() { }
    public string Uri { get; set; }
    public string Title { get; set; }
}

//The following types are in my project and have full control over.
interface IPlaylistEntry
{
    IMediaFile MediaFile { get; }
}
class CPlaylistEntry<T> : IPlaylistEntry where T : IMediaFile
{
    public CPlaylistEntry() { }
    public T MediaFile { get; set; }
}

IMediaFileには複数の実装がありますが、私は1つしか示していません。私のPlaylistEntryクラスは、これらのさまざまな実装のさまざまな特性を可能にするために汎用的な引数をとります。私はIPlaylistEntryを使って作業します。

だから私はそれを次のようにモデル化し始めました:

var mediaFile = _modelBuilder.Entity<CMediaFile>();
mediaFile.Key(e => e.Uri);
mediaFile.Index(e => e.Uri);
mediaFile.Property(e => e.Title).MaxLength(256).Required();

var mediaFilePlaylistEntry = _modelBuilder.Entity<CPlaylistEntry<CMediaFile>>();
mediaFilePlaylistEntry.Key(e => e.MediaFile);
mediaFilePlaylistEntry.Reference(e => e.MediaFile).InverseReference();

簡単なテストとして、私はCPlaylistEntry <>を無視し、次のようにします:

dbContext.Set<CMediaFile>().Add(new CMediaFile() { Uri = "irrelevant", Title = "" });
dbContext.SaveChanges()

これはスローされます:

NotSupportedException:エンティティタイプ 'CPlaylistEntry'の 'MediaFile'に値が設定されておらず、 'CMediaFile'タイプのプロパティに値ジェネレータが使用できません。エンティティを追加する前にプロパティの値を設定するか、 'CMediaFile'タイプのプロパティの値ジェネレータを設定してください

私はこの例外を理解していないし、私はCMediaFileエンティティを格納しようとしているときにCPlaylistEntryがなぜ現れているのかわかりません。私はこれが私のモデル定義に関連していると推測しています - 具体的にはCPlaylistEntryの主キーを単純な型ではなく、複雑な型 - 別の主体として定義しています。しかし、私は、複雑な型は既に宣言されている独自の主キーを持っているため、Eriが文字列Uriに沸き立つことを理解するのに十分なほどスマートになると期待しており、プロパティをその型の外部キーとして宣言しています。

EFでこれらのクラスをモデル化することは、対応するデータベース表がどのようなものに近くなるかを根本的に再設計することなく可能ですか?私は過去にEF6データベースを扱ってきました。これはコードファーストパターンへの私の最初の試みであり、データベースが私のモデル定義に似ているかもしれないという混乱を、 .NETで対話する「きれいな」クラスを維持してください。

これらのタイプとその関係の詳細な説明が必要な場合は、尋ねてみてください。

受け入れられた回答

これは現在サポートされていません(最終的にそうでないかどうかは不明です)。私はあなたのモデルを少し変更して再作成しようとしました。データベースを作成しようとすると、次のようになります。

System.NotSupportedException: 'PlaylistEntry`1MediaFile'プロパティは現在サポートされていない 'MediaFile'タイプであるため、マップできません。

アップデート1

MediaFileをキーにしているという事実は問題を作り出していると私は思っています。私はあなたのモデルにいくつかの変更を加えました。私はこれがあなたの目的のために否定的なものを壊さないことを望みます:

public interface IPlaylistEntry<T>
    where T : IMediaFile
{
    T MediaFile { get; set; }
}

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public int Id { get; set; }
    public string PlaylistInfo { get; set; } //added for testing purposes
    public T MediaFile { get; set; }
}

マッピング:

protected override void OnModelCreating(ModelBuilder builder)
  {
     builder.ForSqlServer().UseIdentity();

     builder.Entity<MediaFile>().ForRelational().Table("MediaFiles");
     builder.Entity<MediaFile>().Key(e => e.Uri);
     builder.Entity<MediaFile>().Index(e => e.Uri);
     builder.Entity<MediaFile>().Property(e => e.Title).MaxLength(256).Required();

     builder.Entity<PlaylistEntry<MediaFile>>().ForRelational().Table("MediaFileEntries");
     builder.Entity<PlaylistEntry<MediaFile>>().Key(e => e.Id);
     builder.Entity<PlaylistEntry<MediaFile>>().Reference(e => e.MediaFile).InverseReference();
 }

使用法:

  var mediaFile = new MediaFile() {Uri = "irrelevant", Title = ""};
  context.Set<MediaFile>().Add(mediaFile);
  context.SaveChanges();

  context.Set<PlaylistEntry<MediaFile>>().Add(new PlaylistEntry<MediaFile>
  {
      MediaFile = mediaFile,
      PlaylistInfo = "test"
  });

  context.SaveChanges();

これは正常に動作し、正しいデータをデータベースに保存します。

次の方法を使用してデータを取得できます。

  var playlistEntryFromDb = context.Set<PlaylistEntry<MediaFile>>()
         .Include(plemf => plemf.MediaFile).ToList();

アップデート2

あなたはアイデンティティをキーにしたくないので、PlaylistEntryとMediaFileの間の関係に使用されるUriプロパティをplaylistentryクラスに追加することができます。

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public string Uri { get; set; }
    public string PlaylistInfo { get; set; }
    public T MediaFile { get; set; }
}

この場合のマッピングは次のようになります。

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<MediaFile>().ForRelational().Table("MediaFiles");
        builder.Entity<MediaFile>().Key(e => e.Uri);
        builder.Entity<MediaFile>().Index(e => e.Uri);
        builder.Entity<MediaFile>().Property(e => e.Title).MaxLength(256).Required();

        builder.Entity<PlaylistEntry<MediaFile>>().ForRelational().Table("MediaFileEntries");
        builder.Entity<PlaylistEntry<MediaFile>>().Key(e => e.Uri);
        builder.Entity<PlaylistEntry<MediaFile>>().Reference(e => e.MediaFile).InverseReference().ForeignKey<PlaylistEntry<MediaFile>>(e => e.Uri);
    }

データを挿入するための使用方法は同じです:

 var mediaFile = new MediaFile() { Uri = "irrelevant", Title = "" };
 context.Set<MediaFile>().Add(mediaFile);
 context.SaveChanges();

 context.Set<PlaylistEntry<MediaFile>>().Add(new PlaylistEntry<MediaFile>
 {
     MediaFile = mediaFile,
     PlaylistInfo = "test"
 });

 context.SaveChanges();

上記のコードは、外部キーとして使用されるため、PlaylistEntry Uriプロパティに「無関係」を配置します。

また、データを取得するには:

    var mediaFiles = context.Set<PlaylistEntry<MediaFile>>().Include(x => x.MediaFile).ToList();

両方のテーブルのUriフィールドで結合が行われます。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ