我的模型有一个非抽象的基类,并没有定义任何键(它是一个我无法修改的外部定义的类)。相反,我将具有MyID
属性的派生类定义为关键。像这样:
public class MyBaseClass // From external assembly
{
//public int ID { get; set; }
public string Name { get; set; }
}
public class MyClass // From external assembly
{
public int ID { get; set; }
public List<MyBaseClass> Objects { get; set; }
}
public class MyDerivedClass : MyBaseClass
{
public Guid MyID { get; set; }
public MyDerivedClass()
{
MyID = Guid.NewGuid();
}
}
public class MyClasses : DbContext
{
public DbSet<MyClass> Classes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyDerivedClass>().HasKey(entity => entity.MyID);
modelBuilder.Entity<MyDerivedClass>().Map(entity =>
{
entity.MapInheritedProperties();
entity.ToTable("MyBaseClass");
});
modelBuilder.Ignore<MyBaseClass>();
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer<MyClasses>(new DropCreateDatabaseIfModelChanges<MyClasses>());
var myClass = new MyClass() // Just as example, in real code is somethog like: MyClass myClass = ExtenalAssembly.getMyClass()
{
ID = 0,
Objects = new List<MyBaseClass>()
{
new MyBaseClass()
{
//ID = 0,
Name = "My Test Object 1"
},
new MyBaseClass()
{
//ID = 1,
Name = "My Test Object 2"
}
}
};
Mapper.CreateMap<MyBaseClass, MyDerivedClass>();
for (var index = 0; index < myClass.Objects.Count; index++)
{
myClass.Objects[index] = Mapper.Map<MyDerivedClass>(myClass.Objects[index]);
}
var myObjects = new MyClasses();
myObjects.Classes.Add(myClass);
myObjects.SaveChanges();
}
}
如果我注释掉行modelBuilder.Ignore<MyBaseClass>();
,运行时会抛出异常,因为MyBaseClass
没有定义键;另一方面,当我包含该行以保存基类实例的状态但仅保存派生类的实例的状态时,系统不会在生成的表中保留任何数据
如果只保留派生实例的状态,我该怎么办?
答案 0 :(得分:1)
我使用NuGet的EF6.0.1运行你的解决方案,它全部检出(没有错误)。我正确地保留了数据,并且两个字段都按预期保持不变。
如果我正确地读你,听起来你不希望基类的Name
属性映射到EF。如果是这种情况,您可以将此行添加到modelBuilder并重新生成迁移文件。
modelBuilder.Entity<MyDerivedClass>().Ignore(d => d.Name);
这给了我以下“Up”脚本
CreateTable(
"dbo.MyBaseClass",
c => new
{
MyID = c.Guid(nullable: false),
})
.PrimaryKey(t => t.MyID);
运行main之后,只保留ID。
答案 1 :(得分:0)
更改导航集合属性以使用派生类型作为泛型类型参数(毕竟,您告诉EF忽略MyDerivedType
)。这将使事情奏效。
更新:如果您无法更改MyClass
课程,请从MyClass
派生一个新课程,其中包含将MyClass.Objects
转换为List<MyDerivedClass>
并从MyClass
转换的属性并使用这个新派生的类代替MyBaseClass
。
更新2:在通过MyClass.Objects
属性访问时,通过自动将MyDerivedClass
中MyClass2.DerivedObjects
的实例转换为MyBaseClass
的实例,使代码更安全。这允许在MyClass.Objects
列表中添加MyClass2.DerivedObjects
个实例(如问题所示),而不必担心在使用MyClass2
访问时出现无效的强制转换异常。
更新3:再次更新以使MyClass
换行// DbSet property in your DbContext
public DbSet<MyClass2> Classes { get; set; }
// continue to ignore MyBaseClass
...
modelBuilder.Ignore<MyBaseClass>();
...
public class MyBaseClass // From external assembly
{
//public int ID { get; set; }
public string Name { get; set; }
}
public class MyDerivedClass : MyBaseClass
{
public Guid MyID { get; set; }
public MyDerivedClass()
{
MyID = Guid.NewGuid();
}
public MyDerivedClass( MyBaseClass myBaseClass ) : this()
{
// map myBaseClass to `this` here:
this.Name = myBaseClass.Name;
}
}
public class MyClass
{
public int ID { get; set; }
public List<MyBaseClass> Objects { get; set; }
}
public class MyClass2
{
public static implicit operator MyClass( MyClass2 mc2 )
{
return mc2._myClass;
}
public virtual List<MyDerivedClass> Objects
{
get
{
for( int i = 0; i < _myClass.Objects.Count; ++i )
{
var o = _myClass.Objects[ i ];
if( null == ( o as MyDerivedClass ) )
{
_myClass.Objects[ i ] = new MyDerivedClass( o );
}
}
return _myClass.Objects.Cast<MyDerivedClass>().ToList();
}
set
{
_myClass.Objects = value.Cast<MyBaseClass>().ToList();
}
}
public int ID
{
get { return _myClass.ID; }
set { _myClass.ID = value; }
}
private MyClass _myClass;
public MyClass2()
{
_myClass = new MyClass();
}
public MyClass2( MyClass myClass )
{
if( null == myClass )
throw new ArgumentNullException( "myClass" );
_myClass = myClass;
}
}
而不是从中派生
using( var db = new TestContext() )
{
var myClass = new MyClass()
{
ID = 0,
Objects = new List<MyBaseClass>()
{
new MyBaseClass()
{
Name = "Object 1"
},
new MyBaseClass()
{
Name = "Object 2"
}
}
};
var myClass2 = new MyClass2( myClass );
db.Classes.Add( myClass2 );
db.SaveChanges();
}
申请代码:
{{1}}