C# 这些模型可以用EF7表示吗?

C# 这些模型可以用EF7表示吗?,c#,entity-framework-core,C#,Entity Framework Core,我试图在我自己的项目中使用来自另一个程序集的一些类作为实体,我可以使用EF7持久化这些实体,而不是编写一系列非常类似的类,这些类对数据库更加友好 简化版本如下所示: interface IMediaFile { string Uri { get; } string Title { get; set; } } class CMediaFile : IMediaFile { public CMediaFile() { } public string Uri { get

我试图在我自己的项目中使用来自另一个程序集的一些类作为实体,我可以使用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; }
}
接口文件
{
字符串Uri{get;}
字符串标题{get;set;}
}
类CMediaFile:IMediaFile
{
公共CMediaFile(){}
公共字符串Uri{get;set;}
公共字符串标题{get;set;}
}
//以下类型在我的项目中,可以完全控制。
接口IPlaylistEntry
{
IMediaFile媒体文件{get;}
}
类CPlaylistEntry:IPlaylistEntry,其中T:imedifile
{
公共CPlaylistEntry(){}
公共T媒体文件{get;set;}
}
IMediaFile有多个实现,我只展示一个。我的playlingentry类使用一个通用参数为这些不同的实现启用不同的特性,我只使用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();
var mediaFile=\u modelBuilder.Entity();
Key(e=>e.Uri);
Index(e=>e.Uri);
属性(e=>e.Title).MaxLength(256).Required();
var mediafileplaylingentry=_modelBuilder.Entity();
mediafileplaylingentry.Key(e=>e.MediaFile);
MediaFilePlayEntry.Reference(e=>e.MediaFile.InversereReference();
作为一个简单的测试,我忽略CPlaylistEntry,只执行以下操作:

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

NotSupportedException:实体类型“CPlaylistEntry”上的“MediaFile”没有值集,并且没有可用于类型“CMediaFile”属性的值生成器。在添加实体之前为属性设置值,或者为“CMediaFile”类型的属性配置值生成器`

我甚至不理解这个异常,我也不明白当我只尝试存储一个CMediaFile实体时为什么会出现CPlaylistEntry。我猜这与我的模型定义有关——特别是将CPlaylistEntry的主键定义为另一个实体,而不是简单类型,而是复杂类型。不过,我希望EF足够聪明,能够将其归结为字符串Uri,因为该复杂类型已经声明了自己的主键,并且我已经将该属性声明为该类型的外键

是否可以在EF中对这些类进行建模,而无需对它们进行彻底的重新设计,以便更接近相应的数据库表?我在过去第一次使用EF6数据库,所以这是我第一次尝试代码优先模式,我真的希望我能隔离数据库可能看起来像我的模型定义一样的混乱,并保持我在.NET中与之交互的“干净”类

如果需要对这些类型及其关系进行更多解释,只需询问-我正试图保持这一简要说明。

怀疑当前是否支持此功能(不确定最终是否支持)。|我已尝试通过轻微更改重新创建您的模型,在尝试创建数据库时,我得到:

System.NotSupportedException:属性“PlayEntry`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; }
}
公共接口IPlaylistEntry
其中T:IMediaFile
{
T媒体文件{get;set;}
}
公共类播放列表条目:IPlaylistEntry
其中T:IMediaFile
{
公共int Id{get;set;}
公共字符串playlinginfo{get;set;}//添加用于测试目的
公共T媒体文件{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();
 }
模型创建时受保护的覆盖无效(ModelBuilder)
{
builder.ForSqlServer().UseIdentity();
builder.Entity().ForRelational().Table(“媒体文件”);
builder.Entity().Key(e=>e.Uri);
builder.Entity().Index(e=>e.Uri);
builder.Entity().Property(e=>e.Title).MaxLength(256).Required();
builder.Entity().ForRelational().Table(“MediaFileEntries”);
builder.Entity().Key(e=>e.Id);
builder.Entity().Reference(e=>e.MediaFile.inverserereference();
}
用法:

  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 mediaFile=new mediaFile(){Uri=“unrelated”,Title=”“};
context.Set().Add(mediaFile);
SaveChanges();
context.Set().Add(新播放列表项
{
MediaFile=MediaFile,
playlinfo=“测试”
});
SaveChanges();
这样可以将正确的数据保存到数据库中

您可以使用以下方法检索数据:

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

由于您不希望将标识作为密钥,因此可以向PlayEntry类添加Uri属性,该属性将用于PlayEntry和MediaFile之间的关系

public class PlaylistEntry<T> : IPlaylistEntry<T>
    where T : IMediaFile
{
    public string Uri { get; set; }
    public string PlaylistInfo { get; set; }
    public T MediaFile { get; set; }
}
公共类播放列表条目:IPlaylistEntry
其中T:IMediaFile
{
公共字符串Uri{get;set;}
公共字符串播放信息{get;set;}
公共T媒体文件{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);
    }
模型创建时受保护的覆盖无效(ModelBuilder)
{
builder.Entity().ForRelational().Table(“媒体文件”);
builder.Entity().Key(e=>e.Uri);
builder.Entity().Index(e=>e.Uri);
builder.Entity().Property(e=>e.Title).MaxLength(256).Required();
builder.Entity().ForRelational().Table(“MediaFileEntries”);
builder.Entity().Key(e=>e.Uri);
builder.Entity().Reference(e=>e.MediaFile).inverserereference().ForeignKey(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();
var mediaFile=新媒体
    var mediaFiles = context.Set<PlaylistEntry<MediaFile>>().Include(x => x.MediaFile).ToList();