4

遇到 Entity Framework 4中缺乏enum属性支持的问题后,我发现这篇文章描述了一种解决方法:

Entity Framework 4.0 Beta 1 – POCO 枚举支持?

如何OrderStatusWrapper在代码中而不是在设计器中表达数据库列到(如文章中所述)的映射?

更新:

根据提供的答案,我没有意识到我需要OrderStatus用类型替换枚举OrderStatusWrapper,即

代替:

public class Order 
{
    public OrderStatus Status { get; set; }
}

我应该使用:

public class Order 
{
    public OrderStatusWrapper Status { get; set; }
}

这让我更进一步,但是在执行以下代码时:

// 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();
} 

引发以下异常(为简洁起见):

System.Data.SqlClient.SqlException
            消息=无效的列名“值”。

数据库列名为Status。我尝试用以下方式装饰Status房产:

[Column("Status")]

然后

[Column("Status"), TypeName("OrderStatus")]

[Column("Status"), TypeName("OrderStatusWrapper")]

但这并不能解决此异常。

我还尝试删除该Column属性并执行此操作:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Order>()
      .Property(p => p.OrderStatus)
      .HasColumnName("OrderStatus");
}

但我得到以下编译错误:

错误 1 ​​类型“ConsoleApplication1.OrderStatusWrapper”必须是不可为空的值类型,才能在泛型类型或方法“System.Data.Entity.ModelConfiguration.Configuration.Types.StructuralTypeConfiguration.Property( System.Linq.Expressions.Expression>)' [截断路径]

4

2 回答 2

3

以下代码是 Code First CTP5 中映射的样子。在这种情况下,Code First 将自动识别OrderStatusWrapper为复杂类型,这是因为基于Reachability Convention的称为复杂类型发现的概念。您甚至不需要使用fluent API 将 OrderStatusWrapper 显式注册为复杂类型。ComplexTypeAttributeComplexType<T>()

有关更多信息,请查看这篇文章:
使用 Code First CTP5 进行实体关联映射:复杂类型

更新:

由于 CTP5 中的一个错误,如果您想为复杂类型属性使用自定义列名(例如 DB 中 OrderStatusWrapper.Value 的 [Orders].[Status]),那么您必须使用以下内容显式标记它[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
}

由于您正在使用现有数据库,因此您也可以选择关闭数据库中的元数据表:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Conventions
                .Remove<System.Data.Entity.Database.IncludeMetadataConvention>();
}
于 2010-12-19T19:03:47.020 回答
3

在上下文文件中写下:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ComplexType<OrderStatusWrapper>();
            base.OnModelCreating(modelBuilder);
        }

它应该工作。

编辑:

public class Order
{
     public...
     ...
     public OrderStatusWrapper OrderStatus { get; set; }
}

public ActionResult Index()
{
    var result = _context.Orders.Where(o => o.OrderStatus == OrderStatus.ReadyForShipping);

    _context.Orders.Add(new Order{ ..., OrderStatus = OrderStatus.Shipped });

    ...;
}

如果您按照该示例所示以及我在上面显示的那一小段代码(直到编辑:) 应该按预期工作。

编辑 nr2:如果我们的包装器看起来像这样:

public class OrderStatusWrapper
{
    private OrderStatus _status;

    public int Value
    {
        get { return (int)_status; }
        set { _status = (OrderStatus)value; }
    }
    public OrderStatus EnumValue
    {
        get { return _status; }
        set { _status = value; }
    }
    public static implicit operator
         OrderStatusWrapper(OrderStatus status)
    {
        return new OrderStatusWrapper { EnumValue = status };
    }

    public static implicit operator
        OrderStatus(OrderStatusWrapper statusWrapper)
   {
       if (statusWrapper == null) return OrderStatus.OrderCreated;
       else return statusWrapper.EnumValue;
   }
}

数据库采用属性值的名称,因此如果将该属性名称更改为状态,数据库中的列将更改为状态。

于 2010-12-19T18:34:27.787 回答