如何使用代码第一个CTP5将列映射到EF4中的复杂类型? [英] How do I map a column to a complex type in EF4 using code first CTP5?
问题描述
枚举
属性支持我发现这篇文章描述了一个解决方法:如何将数据库列映射到 OrderStatusWrapper
(如文章中所述)代码而不是在设计器中
更新: / p>
根据提供的答案,我没有意识到我需要用 OrderStatus
枚举替换code> OrderStatusWrapper 类型,即
而不是:
public class Order
{
public OrderStatus Status {get;组;
}
我应该使用:
public class Order
{
public OrderStatusWrapper Status {get;组; }
}
这让我进一步,但是执行以下代码时: / p>
//在其他地方定义的OrderContext类:
// public class OrderContext:DbContext
// {
// public DbSet< Order>订单{get;组;
//}
使用(OrderContext ctx = new OrderContext())
{
订单=新订单{Status = OrderStatus.Created; }
ctx.Orders.Add(order);
ctx.SaveChanges();
}
出现以下异常(为简洁起见):
System.Data.SqlClient.SqlException
Message =无效的列名称值。
数据库列命名为状态
。我尝试用以下方式装饰状态
属性:
[Column(Status)]
然后
[列(状态 ),TypeName(OrderStatus)]
和
[Column(Status),TypeName(OrderStatusWrapper)]
但是这并不能解决这个异常。 / p>
我还尝试删除列
属性,然后执行此操作:
modelBuilder.Entity< Order>()
.Property(p => p。 OrderStatus)
.HasColumnName(OrderStatus);
}
但是我收到以下编译错误:
错误1类型ConsoleApplication1.OrderStatusWrapper必须是不可为空的值类型,以便在通用类型或方法System.Data.Entity中将其用作参数T。 ModelConfiguration.Configuration.Types.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression>)'[snipped path]
以下代码是Code First CTP5中的映射方式。在这种情况下,由于名称为复杂类型发现的概念,Code First将自动将 OrderStatusWrapper
识别为复杂类型,该概念基于可达性公约。您甚至不需要使用 ComplexTypeAttribute
或 ComplexType< T>()
流畅的API来显式地将OrderStatusWrapper注册为一个复杂的类型。
有关更多信息,请查看此文章:
实体协会使用代码第一个CTP5映射:复杂类型
更新:
由于CTP5中的错误,如果要为复合类型属性(例如DB中的OrderStatusWrapper.Value的[Orders]] [Status]设置自定义列名称,则必须使用 [ComplexType]
:
public class Order
{
public int OrderId {get;组; }
public DateTime CreatedOn {get;组; }
public OrderStatusWrapper Status {get;组; }
}
[ComplexType]
public class OrderStatusWrapper
{
private OrderStatus _status;
[Column(Name =Status)]
public int Value {
get {return(int)_status; }
set {_status =(OrderStatus)value; }
}
public OrderStatus EnumValue {
get {return _status; }
set {_status = value; }
}
}
public enum OrderStatus
{
OrderCreated,
OrderPayed,
OrderShipped
}
由于您正在使用现有数据库,您还可以选择在数据库中关闭元数据表: / p>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Conventions
.Remove< System.Data.Entity.Database.IncludeMetadataConvention>();
}
Having bumped into the of the lack of enum
property support in Entity Framework 4 I discovered this article which describes a workaround:
How do I express the mapping of a database column to the OrderStatusWrapper
(as described in the article) in code rather than in the designer?
Update:
Based on the answers provided, I hadn't realised that I needed to replace the OrderStatus
enum with the OrderStatusWrapper
type, i.e.
Instead of:
public class Order
{
public OrderStatus Status { get; set; }
}
I should be using:
public class Order
{
public OrderStatusWrapper Status { get; set; }
}
This gets me a bit further, however upon executing the following code:
// OrderContext class defined elsewhere as:
// public class OrderContext : DbContext
// {
// public DbSet<Order> Orders { get; set; }
// }
using(OrderContext ctx = new OrderContext())
{
Order order = new Order { Status = OrderStatus.Created; }
ctx.Orders.Add(order);
ctx.SaveChanges();
}
The following exception is raised (trimmed for brevity):
System.Data.SqlClient.SqlException Message=Invalid column name 'Value'.
The database column is named Status
. I tried decorating the Status
property with:
[Column("Status")]
then
[Column("Status"), TypeName("OrderStatus")]
and
[Column("Status"), TypeName("OrderStatusWrapper")]
But this doesn't resolve this exception.
I also tried removing the Column
attribute and doing this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.Property(p => p.OrderStatus)
.HasColumnName("OrderStatus");
}
But I get the following compile error:
Error 1 The type 'ConsoleApplication1.OrderStatusWrapper' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Data.Entity.ModelConfiguration.Configuration.Types.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression>)' [snipped path]
The following code is how the mappings looks like in Code First CTP5. In this case Code First will automatically recognize OrderStatusWrapper
as a complex type due to a concept called Complex Type Discovery that works based on the Reachability Convention. You don't even need to use ComplexTypeAttribute
or the ComplexType<T>()
fluent API to explicitly register OrderStatusWrapper as a complex type.
For more info please take a look at this post:
Entity Association Mapping with Code First CTP5: Complex Types
Update:
Due to a bug in CTP5, if you want to have a custom column name for your complex type properties (e.g. [Orders].[Status] for OrderStatusWrapper.Value in DB), then you have to explicitly mark it with [ComplexType]
:
public class Order
{
public int OrderId { get; set; }
public DateTime CreatedOn { get; set; }
public OrderStatusWrapper Status { get; set; }
}
[ComplexType]
public class OrderStatusWrapper
{
private OrderStatus _status;
[Column(Name="Status")]
public int Value {
get { return (int)_status; }
set { _status = (OrderStatus)value; }
}
public OrderStatus EnumValue {
get { return _status; }
set { _status = value; }
}
}
public enum OrderStatus
{
OrderCreated,
OrderPayed,
OrderShipped
}
Since you are working with an existing database, you can optionally switch off metadata table in database as well:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Conventions
.Remove<System.Data.Entity.Database.IncludeMetadataConvention>();
}
这篇关于如何使用代码第一个CTP5将列映射到EF4中的复杂类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!