我试图将自己项目中另一个程序集中的某些类用作可以使用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有多种实现,我只展示一种。我的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的主键定义为不是简单类型,而是复杂类型-另一个实体。但是,我希望EF足够聪明,以至于可以将其归结为字符串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
由于您不想以身份作为密钥,因此可以将Uri属性添加到播放列表类中,该类将用于PlaylistEntry和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; }
}
在这种情况下,映射如下所示:
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字段上发生。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句