如何使用代码优先 CTP5 将列映射到 EF4 中的复杂类型?

发布于 2024-10-08 22:54:05 字数 2102 浏览 0 评论 0原文

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

实体框架 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
            Message=Invalid column name 'Value'.

数据库列名为 Status。我尝试用以下方法装饰 Status 属性:

[Column("Status")]

然后

[Column("Status"), TypeName("OrderStatus")]< /code>

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

但这并不能解决此异常。

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

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

但出现以下编译错误:

错误 1 ​​类型“ConsoleApplication1.OrderStatusWrapper”必须是不可为 null 的值类型才能使用它作为泛型类型或方法“System.Data.Entity.ModelConfiguration.Configuration.Types.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression>)”中的参数“T”[截取路径]

Having bumped into the of the lack of enum property support in Entity Framework 4 I discovered this article which describes a workaround:

Entity Framework 4.0 Beta 1 – POCO Enum support?

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]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

厌倦 2024-10-15 22:54:05

在上下文文件中写下:

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

    ...;
}

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

编辑编号2:
如果我们的包装器如下所示:

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;
   }
}

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

in the context file write this:

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

it should work.

EDIT:

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

    ...;
}

if you did as that example shows along with that small piece of code i showed the above (until EDIT:) should work as expected.

EDIT nr2:
If our wrapper looks like this:

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;
   }
}

The database takes the name of the property Value, so if you change that property name to Status, the column in the database would change to Status.

孤城病女 2024-10-15 22:54:05

以下代码是 Code First CTP5 中映射的样子。在这种情况下,由于基于可达性约定的称为复杂类型发现的概念,Code First 会自动将OrderStatusWrapper识别为复杂类型。您甚至不需要使用 ComplexTypeAttributeComplexType() Fluent API 将 OrderStatusWrapper 显式注册为复杂类型。

欲了解更多信息,请查看这篇文章:

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

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>();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文