C# 这些模型可以用EF7表示吗?
我试图在我自己的项目中使用来自另一个程序集的一些类作为实体,我可以使用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
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();